4月24日(金)に
JJUG ナイトセミナ 「Javaのプログラムはどうやって動いているの?」に行って来た。
その内容をメモメモ
■Javaのプログラムはどうやって動いているの?JVM編
アジェンダ
・JVM
・Classファイル
・mainを実行するまで
・バイトコードの実行
桜庭さん@skrbの自己紹介
・Javaチャンピオン
・Java in the BOX
・ITPro Java技術最前線
・ごちそうフォト
JVM
Virtual Machine
プログラミング言語を解釈し
コンピューターで実行するソフトウェア
・JavaVM
・.net CLR
・Small t5alk
・Write Once,Run Anywhere
Java Virtual Machine
バイトコードを解釈して実行
基本はインタープリタ
実行時コンパイル
Just-in-Time Compile
Today's Sample
Classファイル
.java→Javac→.classファイル
クラス定義
フィールド定義
メソッド定義
↓
クラス定義
フィールド定義
バイトコード
定数プール:文字列、リテラル
属性:型パラメータとか
Javap:どういうバイトコードか?
バイトコードの逆アセンブル
javap -p -c クラス名
-p プライベート
-c バイトコード
javap -p -v クラス名
-v バイトコード+定数プール
Java仮想マシン仕様
mainを実行するまで
1.JVM起動
2.クラスロード
3.リンク
4.初期化
5.main実行
JVM起動
JNI_CreateJavaVM()
クラスロード
classファイルの読み込み
使用するクラスを芋づる式にロード
java -verbose:class Test
rt.jar Java9から必要ないのは読み込まないように
リンク
classファイルが正しいかチェック
staticフィールドの初期化
ただし、Javaコードの実行はしない
finalでもnullが入る
クラス間の関係を解決
初期化
staticフィールドの初期化
javaコードも実行 finalの値入る
staticイニシャライザの実行
mainメソッドの実行
Java puzzle:Anniversary
バイトコードの実行
1.キュー
2.でっく(Deque:できゅーではない)
3.スタック
4.リングバッファ
5.マップ(連想配列)
6.リンクドリスト(リスト構造)
java.utilのstackは使ってはいけない
古い
ArrayDequeを使う
スタックがメイン
Stack
LIFO
途中の要素のアクセスはダメ
実行形態
スタックマシン:中間状態をスタックに
JavaVM,.net Framework CLR,PS
レジスターマシン:Intel Core,ARM Cortex
ダルビック
逆ポーランド記法
中間の状態をスタックで取る
ヒープ
メタスペース(パーマネント領域)
スレッドごとにスタックがある
Java Stack
プログラムカウンタ(PC)
フレーム
0番目 This
そのあと引数が積まれる
JVM編conclusion
・マカロンスタック
マカロンは積むもの
Java Javac Classファイル:バイトコード
JVM起動
クラスロード
リンク
初期化
main実行
JVM:Stackマシン
サーバー系はむちゃくちゃ読み込む
互換性:検証でチェック
OracleのJavacとeclipseのJavacでバイトコードは違う
Java SE7までは、互換性は取れている(実行結果は同じ)
ただし、VMの解釈は、実装依存
■Javaのプログラムはどうやって動いているの?GC編
アジェンダ
Why to Use GC
Mark & Sweep GC
Copy GC
世代別GC
Why to Use GC
GC
Garbage Collection
メモリの自動管理
不要になったメモリを自動的に回収
Before GC
自前でメモリ管理
C
malloc(),calloc(),realloc()
free()
問題点
メモリの解放し忘れ
二重開放
無効な参照
メモリ周りのバグは修正が難しい
1959:いちばんはじめのGC
John McCarthy Mark&SweepGC Lisp向け
一般的に使用されだしたのは90年代
CPU、メモリ性能向上
GC
アルゴリズム
ベーシック
Mark&Sweep
参照カウント
Copy
複合
世代別
G1
運用
シリアル
インクリメンタル
コンカレント
パラレル
JavaVM:参照カウントだけない。他はある
デフォルトCMS:コンカレントでMark&Sweep
GC本 中村さん
Mark&Sweep
Mark:使用中のオブジェクトをマーク
Sweep:マークのないオブジェクトを掃除
Rootから芋づる式にマーク→深さ優先探索
先頭から未使用ObjをFreeListへ
Compactionも一緒にやる
→コンパクトにする
いい点
実装がシンプル
参照の書き換えがないので安全(コンパクションしない限り)
→保守的GC
欠点
おそい
Stop-the-worldの時間が長い
ヒープの断片化がおきやすい(コンパクションしない限り)
CopyGC
ヒープを2分割
使用する領域は一方のみ
片方からもう一方へObjをコピー
使用する領域を反転
→コピーすることでコンパクションと同じことができる
利点
stop-the-worldの時間が短い
ヒープの断片化が起きない
高速なアロケーション
欠点
ヒープの仕様効率が悪い
参照の書き換えがある
世代別GC
仮説:若いObjほど早く死ぬ
世代別にヒープ管理を行う
Young世代 高速なGC→Copy
old世代 安定したGC→M&S
Objの年齢:GCを生き延びた回数
世代別GC
Young
servivor1,servivor2,Eden
old
tenured
新しいObjはYoungへ配置→Eden
GC:edenからservivorへ
tenuredがフラグメンテーション→コンパクション→FullGC
領域サイズはチューニングが必要
old世代のGCをなるべく減らす
CMS,G1GCなどの派生GCあり
Conclusion
M&S、Copy、世代別
原理を知って、チューニングに活かす