SlideShare una empresa de Scribd logo
1 de 106
Descargar para leer sin conexión
2016年年9⽉月6⽇日
河内⾕谷清久仁 http://ibm.biz/kawatiya
⽇日本アイ・ビー・エム(株) 東京基礎研究所
(資料料作成協⼒力力:緒⽅方⼀一則,⼩小笠笠原武史,仲池卓也)
PPLサマースクール2016「商⽤用Java処理理系の研究開発」
Java仮想マシンの実装技術
2016/09/061 Java仮想マシンの実装技術 / 河内⾕谷清久仁
JavaTMおよびすべてのJava関連の
商標およびロゴはOracleやその関連
会社の米国およびその他の国にお
ける商標または登録商標です.
©  2016  IBM  Corporation
概要:⽇日本アイ・ビー・エム(株)東京基礎研究所はJava⾔言語の黎黎明期からその処理理系に関する研究開発を
リードし,IBM開発部⾨門と協業して業務アプリケーションの基盤として使われるJava処理理系を世に送り出して
きた.特に,Just-­‐In-­‐TimeコンパイラとJava仮想マシンの主要構成要素については各種の先進的技術を考案し,
世界トップクラスの性能を達成するとともに,多数の学会発表も⾏行行ってきている.本セミナーでは,この商
⽤用Java処理理系の研究開発に関する経験をもとに,以下の内容について述べる.
1	
  Javaの登場と発展(30分,講師:⼩小野寺⺠民也)
1995年年のJavaの登場とその後の受容の過程を概観し,Java登場時にどのような性能上の課題があったかを述
べ,続く2つのセッションへの導⼊入とする.また,性能向上の研究開発における標準ベンチマークの重要さ
についても⾔言及する.
2	
  Java仮想マシンの実装技術(2時間,講師:河内⾕谷清久仁)
Java⾔言語処理理系の実装について詳説する.まずJava仮想マシンの概要について述べ,その主要な構成要素と
して,クラス管理理とインタープリタ,ヒープ管理理とガベージコレクション,スレッド管理理と同期機構,JIT
コンパイラとの連携,などについて説明する.性能改善のために⾏行行った各種⼿手法についても触れる.
3	
  Java	
  Just-­‐In-­‐Timeコンパイラの実装技術(2時間,講師:⽯石崎⼀一明)
Javaの動的コンパイラの実装について詳説する.まず構成の概要について述べ,主な最適化,動的コンパ
イラ特有の最適化,Java⾔言語特有の最適化,について説明する.また,Java⾔言語からSIMDやGPUなどのハー
ドウェア機構を使う試みについても述べる.商⽤用コンパイラの実装に関する経験談についても触れる.
4	
  まとめと展望(1時間,講師:⼩小野寺⺠民也)
まとめとして,プログラミング⾔言語の実装技術の歴史を概観し,Javaの誕⽣生と発展に果たした役割につい
て考えてみたい(内容は予告なく変更更することがありますw).
2016/09/062
商⽤用Java処理理系の研究開発
Java仮想マシンの実装技術 / 河内⾕谷清久仁
©  2016  IBM  Corporation2016/09/063
講師紹介
⼩小野寺 ⺠民也(おのでら たみや) http://ibm.biz/onodera
⽇日本アイ・ビー・エム(株)技術理理事,東京基礎研究所 サービス型コンピューティング 部⻑⾧長.1988年年東京
⼤大学⼤大学院理理学系研究科情報科学専⾨門課程博⼠士課程修了了.同年年⽇日本アイ・ビー・エム(株)⼊入社.以来,
同社東京基礎研究所にて,プログラミング⾔言語およびミドルウェアおよびシステムソフトウェアの研究開
発に従事. 情報処理理学会第41回(平成2年年後期)全国⼤大会学術奨励賞,同平成7年年度度⼭山下記念念研究賞,同平
成16年年度度論論⽂文賞,同平成16年年度度業績賞,各受賞.理理学博⼠士.⽇日本ソフトウェア科学会会員(元・理理事),
情報処理理学会シニア会員,ACM	
  Distinguished	
  Scientist.
河内⾕谷 清久仁(かわちや きよくに) http://ibm.biz/kawatiya
⽇日本アイ・ビー・エム(株)シニア・テクニカル・スタッフ・メンバー,東京基礎研究所 ディープ・コン
ピューティング&アナリティクス 部⻑⾧長.1987年年東京⼤大学⼤大学院理理学系研究科情報科学専攻修⼠士課程修了了.
同年年⽇日本アイ・ビー・エム(株)⼊入社.以来,同社東京基礎研究所にてOSやプログラミング⾔言語処理理系な
どの研究に従事.最近は,Javaの性能問題分析などにも携わる.博⼠士(政策・メディア).1994年年情報処
理理学会⼤大会奨励賞,2005年年同・論論⽂文賞,2008年年⽇日本ソフトウェア科学会⾼高橋奨励賞,各受賞.⽇日本ソフト
ウェア科学会編集副委員⻑⾧長(元・理理事),情報処理理学会シニア会員,ACM	
  Distinguished	
  Engineer.
⽯石崎 ⼀一明(いしざき かずあき) http://ibm.biz/ishizaki
⽇日本アイ・ビー・エム(株)東京基礎研究所 リサーチ・スタッフ・メンバー.1992年年早稲⽥田⼤大学理理⼯工学研
究科修⼠士課程修了了.同年年⽇日本アイ・ビー・エム(株)⼊入社.以来,同社東京基礎研究所にて,Fortran⾔言語
の並列列化コンパイラ,Java⾔言語の動的コンパイラ,Python⾔言語の動的コンパイラ,などのプログラミング
⾔言語処理理系の研究に従事.最近は,JavaやApache	
  Sparkからの,GPUその他アクセラレータ活⽤用⽅方法に興味
を持つ.情報処理理学会平成16年年度度業績賞受賞.博⼠士(情報科学).⽇日本ソフトウェア科学会理理事,情報処
理理学会会員,ACM	
  Senior	
  Member.
Java仮想マシンの実装技術 / 河内⾕谷清久仁
©  2016  IBM  Corporation
概要:Java⾔言語処理理系の実装について詳説する.まずJava仮想マシンの概要について述べ,その
主要な構成要素として,クラス管理理とインタープリタ,ヒープ管理理とガベージコレクション,
スレッド管理理と同期機構,JITコンパイラとの連携,などについて説明する.性能改善のため
に⾏行行った各種⼿手法についても触れる.
§ カバーする内容
– クラス管理理
– メソッド呼び出しとJIT連携
– バイトコードとインタープリタ
– オブジェクト管理理とGC
– スレッド管理理と同期機構
– 例例外処理理
– (JITコンパイラ超⼊入⾨門)
無記名アンケートへのご協⼒力力をお願いします
(⼀一部だけの回答も可能です)
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁4
Java仮想マシンの実装技術
クラス管理 オブジェクト
管理
インタープリタ
JIT
コンパイラ
JITコンパイラ
生成コード
実行時
プロファイラ
クラスデータ
(Java  バイト
コード)
Javaヒープ
(Java  オブ
ジェクト)
Javaスタック
(ローカル変数,
オペランドスタック)
Java仮想マシン(Java  VM)
Java同期
ランタイム
Java例外処理
ランタイム
JVM
ランタイム
©  2016  IBM  Corporation
§ この講演では,⻘青で囲ったもの
について説明する
– JITコンパイラとプロファイラ
については,次の講演で詳説
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁5
Java	
  VMの主要コンポーネントとデータ構造
クラス管理
オブジェクト
管理
インタープリタ
JIT
コンパイラ
JITコンパイラ
生成コード
実行時
プロファイラ
クラスデータ
(Java  バイト
コード)
Javaヒープ
(Java  オブ
ジェクト)
Javaスタック
(ローカル変数,
オペランドスタック)
OS  /  標準ライブラリ
Java仮想マシン(Java  VM)
Java同期
ランタイム
Java例外処理
ランタイム
JVM
ランタイム
Java
ソースコード
(.javaファイル)
javac
クラスファイル
(.classファイル,
.jarファイル)
プログラム作成時に
行う処理
©  2016  IBM  Corporation
Javaクラスファイルの作成と実⾏行行
6 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁
Java
ソースコード
(.javaファイル)
javac
クラスファイル
(.classファイル,
.jarファイル)
プログラム作成時に
行う処理
class  Hello  {
public  static  void  main(String[  ]  args)  {
System.out.println("Hello  Java");;
}
}
Hello.java
$  javac Hello.java
$  ls
Hello.class Hello.java
$ java Hello
Hello Java
$  
©  2016  IBM  Corporation
§ クラスごとに作られる,構造を持ったバイナリファイル
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁7
クラスファイル
0xCAFEBABE
major_versionは,「javac -­target」のJRE
バージョンによって変わる(45~52)
定数表(リテラル,識別子など)
このクラスで定義しているメソッドの
情報(継承したものは含まない)
クラスのアクセス権や
親クラスなどのメタ情報
Implements  している
インターフェースの一覧
クラス内のフィールドの一覧
バイトコード,デバッグ情報など.
Attributeセクションは何個あってもよい
“The	
  Java	
  Virtual	
  Machine
Specification”	
  より
クラス管理理
©  2016  IBM  Corporation
§ クラスファイルを読み込み,
そのライフサイクルを管理理
するコンポーネント
§ サブコンポーネント
– クラスローダ
§ クラスファイルを検索索
し,メモリ(クラス
データ領領域)に展開
– ベリファイア
§ ロードしたクラスファ
イルにエラーがないこ
とを確認
– Constant	
  pool(定数表)
§ リテラルやシンボル情報を保持
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁9
クラス管理理
クラス管理
オブジェクト
管理
インタープリタ
JIT
コンパイラ
JITコンパイラ
生成コード
実行時
プロファイラ
クラスデータ
(Java  バイト
コード)
Javaヒープ
(Java  オブ
ジェクト)
Javaスタック
(ローカル変数,
オペランドスタック)
Java仮想マシン(Java  VM)
Java同期
ランタイム
Java例外処理
ランタイム
JVM
ランタイム
Java
ソースコード
(.javaファイル)
javac
クラスファイル
(.classファイル,
.jarファイル)
プログラム作成時に
行う処理
©  2016  IBM  Corporation
§ メモリ上に読み込んだクラスファイルをJava	
  VMに渡して,クラスとして登録する
– クラスパスに従ってクラスファイルを探し,クラスデータ領領域に読み込む
– クラスファイルの構造をメモリ上に
直接⽣生成してもよい
§ クラスローダ⾃自体もJavaオブジェクト
– java.lang.ClassLoaderクラス(のサブ
クラス)のインスタンス
– Java	
  VMがデフォルトで⽣生成するもの
が3個ある
– ユーザが⽣生成することも可能
§ クラスアンロード
– 参照されなくなったクラスは,
クラスローダ単位でアンロード可能
– 動的置き換え可能なモジュールの
実装に利利⽤用されている
§ EclipseなどのプラグインやEJB
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁10
クラスローダ
クラスデータ領域
ユーザプログラムの
クラス群
System
class  loader
標準クラス群
Bootstrap  
class    loader
jre/lib/ext にある
JARファイルから
ロードされたクラス
群
Extension  
class  loader
Helloクラス
constant_pool
Field定義
Method定義
バイトコード,
デバッグ情報など
java.lang.Object
java.lang.String
Hello.class読み込み後のクラスデータ構造
©  2016  IBM  Corporation
クラスデータ領域
ロードされたクラス(イメージ)
11 Java仮想マシンの実装技術2016/09/06
クラスS
constant_pool
フィールド定義
S.m1の
バイトコード
S.m2の
バイトコード
管理情報
S.m1の
メソッド情報
vtable
S.m2の
メソッド情報
クラスA
constant_pool
フィールド定義
管理情報
vtable
クラスB
constant_pool
フィールド定義
管理情報
vtable
A.m2の
メソッド情報
A.m3の
メソッド情報
B.m3の
メソッド情報
B.m3の
バイトコード
itable
A.m2の
バイトコード
A.m3の
バイトコード
itable
itable
class  S  {
int val =  1234;;
void  m1()  {  …  }
void  m2()  {  …  }
}
interface  I  {  void  m3();;  }
class  A  extends  S
implements  I  {
void  m2()  {  …  }
void  m3()  {  …  }
}
class  B  implements  I,J  {
void  m3()  {  …  }
}
©  2016  IBM  Corporation
クラスデータ領域 § オブジェクトのクラスに
よって,呼ばれるメソッ
ドが変わる
§ JITされたコードがあれば,
そちらが呼ばれる
2016/09/06 Java仮想マシンの実装技術12
メソッド管理理:仮想メソッドの呼び出し
class  S  {
int val =  1234;;
void  m1()  {  …  }
void  m2()  {  …  }
}
interface  I  {  void  m3();;  }
class  A  extends  S
implements  I  {
void  m2()  {  …  }
void  m3()  {  …  }
}
class  B  implements  I,J  {
void  m3()  {  …  }
}
クラスS
constant_pool
フィールド定義
S.m1の
バイトコード
S.m2の
バイトコード
管理情報
S.m1の
メソッド情報
vtable
[1]  (m1)
[2]  (m2)
クラスA
constant_pool
フィールド定義
A.m2の
バイトコード
管理情報
vtable
[1]  (m1)
[2]  (m2)
[3]  (m3)
S.m2の
メソッド情報
A.m2の
メソッド情報
A.m3の
メソッド情報
S  p  =  new  S();;
p.m2();;  //  à S.m2
S  q  =  new  A();;
q.m2();;  //  à A.m2
p
q
A.m2の
JITされた
コード
interface  I
m3àvtable[3]
A.m3の
バイトコード
©  2016  IBM  Corporation
クラスデータ領域
§ インタフェース関数の呼
び出しは,同じ名前でも
同じvtableオフセットに
ならない
§ クラスデータのitableを
スキャンして対応するイ
ンタフェースを探し,メ
ソッドに対応するvtable
エントリを得る
2016/09/06 Java仮想マシンの実装技術13
メソッド管理理:インタフェースメソッドの呼び出し
class  S  {
int val =  1234;;
void  m1()  {  …  }
void  m2()  {  …  }
}
interface  I  {  void  m3();;  }
class  A  extends  S
implements  I  {
void  m2()  {  …  }
void  m3()  {  …  }
}
class  B  implements  I,J  {
void  m3()  {  …  }
}
クラスA
constant_pool
フィールド定義
管理情報
vtable
[1]  (m1)
[2]  (m2)
[3]  (m3)
クラスB
constant_pool
フィールド定義
管理情報
vtable
[1]  (m3)
A.m2の
メソッド情報
A.m3の
メソッド情報
B.m3の
メソッド情報
B.m3の
バイトコード
I  p  =  new  A();;
p.m3();;  //  à A.m3
I  q  =  new  B();;
q.m3();;  //  à B.m3
interface  “I”
m3àvtable[3]
A.m2の
バイトコード
A.m3の
バイトコード
interface  “I”
m3àvtable[1]
interface  “J”
…
…
©  2016  IBM  Corporation2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁14
Javaバイトコード
class  Hello  {
static  int val =  1234567;;
private  void  Hello() {
super();;
}
public  static  void  main(…) {
System.out.
println("Hello  Java");;
System.out.
println(val);;
}
}
Hello.java
class  Hello  extends  java.lang.Object {
static  {}
0:      ldc #7;;    //int 1234567
2:      putstatic #5;;    //Field  val
5:      return
private  void  <init>();;
0:    aload_0
1:    invokespecial #1
4:    return
public  static  void  main(java.lang.String[]);;
0:      getstatic #2;;    //Field      java.lang.System.out
3:      ldc #3;;    //String    "Hello  Java"
5:      invokevirtual #4;;    //Method  println(String)
8:      getstatic #2;;    //Field      java.lang.System.out
11:      getstatic #5;;    //Field      val
14:      invokevirtual #6;;    //Method  println(int)
17:      return
}
Hello.classのバイトコード
javac
§ Javacが暗黙に⽣生成するメソッドがある
§ 多くの命令令が「定数表」を参照
©  2016  IBM  Corporation2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁15
定数表(Constant	
  Pool)
class  Hello  extends  java.lang.Object {
static  {}
0:      ldc #7;;    //int 1234567
2:      putstatic #5;;    //Field  val
5:      return
private  void  <init>();;
0:    aload_0
1:    invokespecial #1
4:    return
public  static  void  main(java.lang.String[]);;
0:      getstatic #2;;    //Field      java.lang.System.out
3:      ldc #3;;    //String    "Hello  Java"
5:      invokevirtual #4;;    //Method  println(String)
8:      getstatic #2;;    //Field      java.lang.System.out
11:      getstatic #5;;    //Field      val
14:      invokevirtual #6;;    //Method  println(int)
17:      return
}
Hello.classのバイトコード
String  "Hello  Java"
1234567
System.out
java.lang.System
"out"
PrintStrem.println(String)
java.io.PrintStream
"println"
"(Ljava/lang/String;;)V"
Fieldref
Methodref
Name&Type
UTF8
UTF8
UTF8
String
Type
val
Int
Object.<init>()
PrintStrem.println(int)
Index
0
1
2
3
4
5
6
7
9
11
12
14
15
16
Class
Methodref
println(String)
8
Class
Fieldref
Methodref
"Hello  Java"UTF8
"Ljava/io/PrintStream;;"UTF8 13
"Ljava/lang/System;;"UTF8 10
Constant_pool
©  2016  IBM  Corporation
§ Constant	
  poolは,クラスごとに作成されるデータ構造で,以下の内容を保持
– プログラム中のリテラル値
– フィールドやメソッドへの参照
§ シンボル名(クラス名,メソッド名など)
§ Resolve後の状態
§ Resolve
– フィールドやメソッドへの参照を解決する処理理
§ その参照への,初回のアクセス時に⾏行行われる
§ 参照先クラスがロードされていなければロードする
§ アクセス権のチェックが⾏行行われる
– Resolve時に,参照情報のデータ形式を最適化することが多い
§ クラスロード直後は,参照対象は⽂文字列列形式で保持される
§ Resolve後は,参照対象へのポインタを保持するように書き換えられる
– ⼀一旦Resolveされればその後は⾼高速に参照可能
§ インタープリタでResolveしてしまい,JITedコードではResolve後の値を使うのがよい
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁16
シンボル参照の解決(Resolve)
Stringオブジェクトへの参照
1234567
&System.out
&PrintStrem.println(String)
Fieldref
Methodref
String
&val
Int
&Object.<init>()
&PrintStrem.println(int)
0
1
2
3
4
5
6
7
Methodref
Fieldref
Methodref
Resolve後のconstant pool
インタープリタ
©  2016  IBM  Corporation
§ インタープリタとJust-­‐in-­‐Time(JIT)コンパイラ
を組み合わせる処理理系が多い
– インタープリタだけを使う処理理系や,
JITコンパイラだけの処理理系(Jikes RVMなど)
もある
§ Ahead-­‐of-­‐Time(AOT)コンパイラを使う処理理系
もある
– Real-­‐time	
  Javaや,巨⼤大アプリの起動時間
短縮に有効
§ 実⾏行行時プロファイラを⽤用いて,JITコンパイラ
による最適化に有益な情報を収集することも
ある
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁18
バイトコードの実⾏行行(インタープリタ)
クラス管理 オブジェクト
管理
インタープリタ
JIT
コンパイラ
JITコンパイラ
生成コード
実行時
プロファイラ
クラスデータ
(Java  バイト
コード)
Javaヒープ
(Java  オブ
ジェクト)
Javaスタック
(ローカル変数,
オペランドスタック)
Java仮想マシン(Java  VM)
Java同期
ランタイム
Java例外処理
ランタイム
JVM
ランタイム
©  2016  IBM  Corporation
§ スタック・アーキテクチャの命令令セット
– 操作対象のスタックを「オペランド・スタック」と呼ぶ
– 基本的に型付きの命令令(スタック要素も型付き)
§ 1〜~3バイトの可変⻑⾧長(⼀一部例例外あり)
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁19
Javaバイトコード
0x60
opcode  
(0x60)
1  byte
iadd
0xb4getfield   0x01
opcode
(0xb4)
1  byte
0x23
0x1234
0x5678 0x68AC
Field  valObj  ref
SP
SP
SPSP
バイトコード オペランドスタックの操作
operand
(0x0123)
©  2016  IBM  Corporation
§ 実⾏行行中のメソッドの「フレーム」が保持される領領域
§ フレームに格納されるデータ
– カレントクラスなどのリンク情報
– メソッド呼び出しチェーン情報
– ローカル変数
§ メソッド呼び出し時は,callerとcalleeのフレームの
⼀一部が重なる
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁20
Javaスタック
SP
ローカル
変数領域
SP
ローカル
変数領域
0x1234
obj1
0x1234
ローカル
変数領域
obj1.foo(2)
の呼び出し
2
Frame  
data
Frame  
data
Frame  
data
Callerの
フレーム
Callerの
フレーム
Calleeの
フレーム
Callee
の引数
Callerの
スタック
Callerの
スタック obj1
2
©  2016  IBM  Corporation
§ Mixed-­‐mode	
  Execution
– インタープリタとJITコンパイラを併⽤用する実⾏行行⽅方式
– 実⾏行行頻度度の⾼高いところだけ,実⾏行行中にコンパイルしてネイティブコードに変換
– この講演では,インタープリタにフォーカス(JITについては次の講演で)
§ バイトコード・インタープリタの基本構造
– デコード・ループ
§ 1命令令読み込んで,対応するハンドラを呼び出し,ハンドラから戻ってきたら次の命
令令を読み込むループ
– ハンドラ(群)
§ バイトコード命令令で定義された処理理を⾏行行うサブルーチン
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁21
バイトコードの実⾏行行
デコード・
ループ
ハンドラ1
ハンドラ2
バイトコード
©  2016  IBM  Corporation
§ 基本構造をC⾔言語で実装するなら,ハンドラごとに関数を作る
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁22
バイトコード・インタープリタの基本的な実装例例
char  *pc  =  getBytecodeAddr();
int *sp =  getStackBottom();
void
(*decodeTbl[])(char**,int**)={
&op00_handler,   /*0x00*/
...
&op04_handler,   /*0x04*/
...
&op60_handler,   /*0x60*/
...  };
while(TRUE)   {
(*decodeTbl[*pc++])(&pc,&sp);
}
デコード・ループ
0x1234
0x5678 0x68ACiadd
SP
SP
op00_handler(char   **pc,int **sp){
/*  0x00:  nop */
return;  }
op60_handler(char   **pc,int **sp){  
/*  0x60:  iadd */
(*sp)[1]   +=  (*sp)[0];   ++*sp;
return;  }
op04_handler(char   **pc,int **sp){  
/*  0x04:  iconst_1   */
(-­‐-­‐*sp)[0]  =  1;
return;  }
©  2016  IBM  Corporation
インタープリタの⾼高速化
23 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁
©  2016  IBM  Corporation
§ プログラム起動時は,JITコンパイルしない⽅方が速い [Suganuma’01]
– その場合,インタープリタの⾼高速化により起動時間を短縮できる
§ また,JITコンパイルするメソッドを減らせば,JITではなくプログラム実⾏行行に時間を使える
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁24
インタープリタ⾼高速化の必要性
[Suganuma ‘01]  T.  Suganuma
et  al.    A  Dynamic  Optimization
Framework  for  a  Java  Just-­In-­
Time  Compiler.    OOPSLA  ’01
遅い←→速い
スタートアップの性能⽐比較
全部full-­‐JITす
るととても遅い
JITしない⽅方が
アプリ起動は速い
Java:	
  IBM	
  JDK	
  1.3.0
HW:	
  Pentium	
  III	
  600	
  MHz,	
  512MB	
  Memory
OS:	
  Windows	
  2000	
  SP1
©  2016  IBM  Corporation
§ 頻繁に分岐命令令を実⾏行行するので,コードが分断される
– デコード・ループもハンドラも,短く,並列列度度の低いコード
§ ループであっても,命令令読み込みとデコードを繰り返す
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁25
バイトコード・インタープリタのオーバーヘッド
TOS: Top of Stack
i2s
ハンドラ
ineg
ハンドラ
ifgt
ハンドラ
iload_3
ハンドラ
例:「while(  (short)(-­x)  >  0  );;」のデコード操作
xをpush 符号反転 short型に変換
TOS>0なら
ジャンプ
デコード・
ループ
ff faバイトコード 9d93741d
©  2016  IBM  Corporation
§ デコード・ループを全てのハンドラにコピーして間接分岐の実⾏行行回数を減らす
– 各ハンドラの最後で次のバイトコードをデコードし,そのハンドラへ直接ジャンプする
§ アドレス計算の⾼高速化⼿手法もいろいろある
– ハンドラを固定サイズにしてバイトコード順に並べれば,算術演算でアドレス取得も可能
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁26
解決法の例例:Threaded	
  Code	
  [Bell’73,	
  Ritter’80]
iload_3
ハンドラ
ineg
ハンドラ
バイト
コード
&iload_3
&i2s
&ineg
ハンドラ
アドレス
表
デコード&
ジャンプ
デコード&
ジャンプ
デコード&ジャンプ
1d
74
93
©  2016  IBM  Corporation
§ スタック・アーキテクチャの仮想マシンでは,
スタック・トップ(Top	
  of	
  Stack=TOS)近辺の値を頻繁にアクセスする
§ 同じメモリを何度度もアクセスする場合がある
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁27
スタック・アーキテクチャ仮想マシンのボトルネック
SP
0xFFFF
SP
0x0001
i2s
ハンドラ
ineg
ハンドラ
ifgt
ハンドラ
iload_3
ハンドラ
例:「while(  (short)(-­x)  >  0  );;」のスタック操作
xをpush 符号反転 short型に変換
TOS>0なら
ジャンプ
0x0001
SP
SP
SP
©  2016  IBM  Corporation
§ スタック・トップ(TOS)近辺の値をレジスタにキャッシュする
– Write-­‐through	
  cacheかwrite-­‐backにするかは,実装依存
§ 問題点
– 常にTOSをキャッシュすると,無駄な読み込みが発⽣生する
– TOSが無効な状況を認めると,実⾏行行時チェックが必要になる
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁28
解決法の例例:Stack	
  Caching
0x1234
0x5678 0x68AC
SP
SP
iadd
ハンドラ
0x1234
0x5678 0x68AC
SP
SP
iadd
ハンドラ
0x1234
TOSレジスタ
0x68AC
TOSレジスタ
Stack  Cachingなし Stack  Cachingあり
©  2016  IBM  Corporation
§ 効率率率よく,キャッシュ要素数を可変にする技術
§ Step-­‐1:キャッシュしている要素数ごとに
別々のハンドラを⽤用意する
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁29
改良良:Dynamic	
  Stack	
  Caching	
  [Ertl’95]
0x5678
SP
SP
iadd
(c1àc1)
0x1234
TOSレジスタ
0x68AC
TOSレジスタ
キャッシュ要素数=1
のハンドラの動作
SP SP
iadd
(c2àc1)
0x1234
TOSレジスタ
0x68AC
TOSレジスタ
0x5678
NOSレジスタ
キャッシュ
要素数=2
NOS: Next of Stack
0x1234
0x5678
SP
SP
iadd
(c0àc1)
0x68AC
TOSレジスタ
キャッシュ要素数=0
のハンドラの動作
キャッシュ
要素数の変化
©  2016  IBM  Corporation
§ Step-­‐2:キャッシュしている要素数ごとに⽤用意したハンドラでステートマシンを構成して,
キャッシュしている要素数を管理理
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁30
改良良:Dynamic	
  Stack	
  Caching	
  [Ertl’95]
iadd
(c0àc1)
iadd
(c1àc1)
iadd
(c2àc1)
iconst_1
(c0àc1)
iconst_1
(c1àc2)
iconst_1
(c2àc2)
ifeq
(c0àc0)
ifeq
(c1àc0)
ifeq
(c2àc1)
iload_3
(c0àc1)
iload_3
(c1àc2)
iload_3
(c2àc2)
例:「if (  x+1  ==  0  )」のハンドラ呼び出しフロー
xをpush 1をpush 加算
TOS==0なら
ジャンプ
キャッシュ要素数=2
キャッシュ要素数=1
キャッシュ要素数=0
©  2016  IBM  Corporation
§ プロセッサ内部では,メモリの読み書きは常にワード境界に合わせた動作をする
– ワード単位でない場合は,適宜エミュレートする
§ バイトコードの読み込みでは,同じワードを何度度も読込む
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁31
バイトコード読み込みのメモリアクセスの⾮非効率率率性
ff fa ??バイトコード 9d93741d
74
93
9d
ff fa
ワード境界
オペコード0x74を読込み
オペコード0x93を読込み
オペコード0x9dを読込み
オペランド0xfffaを読込み
例:「while(  (short)(-­x)  >  0  );;」のデコード操作
©  2016  IBM  Corporation
§ しかし,バイトコード列列をワード単位でレジスタにキャッシュすると,
バイトコードのワード内オフセットのチェックが必要になる
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁32
解決法の例例:バイトコードをワード単位でキャッシュ
例:「while(  (short)(-­x)  >  0  );;」のデコード操作
ff fa 1cバイトコード 9d93741d
74
93
9d
ff fa
ワード境界
オペコード0x74を読込み
オペコード0x93を読込み
オペコード0x9dを読込み
オペランド0xfffaを読込み
レジスタにキャッシュ ff fa 1c9d9374
©  2016  IBM  Corporation
§ オペコードのワード内位置ごとに,別々のバイトコード・ハンドラを⽤用意し,
ステートマシンで現在のワード内位置を追跡する
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁33
改良良:Position-­‐based	
  handler	
  customization	
  [Ogata’02]
ff fa 1cバイトコード 9d93741d
ワード境界
レジスタにキャッシュ
(Bytecode  Prefetch  Register)
ff fa 1c9d9374
ineg
(b0àb1)
next  opcode
=  BPR0[1]
ineg
(b1àb2)
next  opcode
=  BPR0[2]
ineg
(b2àb3)
next  opcode
=  BPR0[3]
ineg
(b3àb0)
next  opcode
=  BPR1[0]
BPR0  =  BPR1
Load  BPR1
BPR0 BPR1
9374
BPR0
9374
BPR0
9374
BPR0
9374
BPR0 BPR1
例:ineg(0x74)ハンドラの4つのバリエーション
©  2016  IBM  Corporation
SPECjvm 98 jBYTEmark JavaGrande
相対性能
§ ベース・インタープリタ(Threaded	
  code)からの速度度変化
– DS=Dynamic	
  Stack	
  Caching,WT=Write-­‐throughで常に1個キャッシュ
– PHC=ワード単位でバイトコードをキャッシュ,PSD=投機的にデコード
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁34
パフォーマンス⽐比較遅い←→速い
※ このグラフはゼロ始まりでないので注意
Java:	
  IBM	
  JDK	
  1.3.0
HW:	
  POWER3	
  400MHz,	
  768MB	
  Memory
OS:	
  AIX	
  4.3.3
※どの最適化がよく効くかは,
プロセッサの特性によっても異異なる
オブジェクト管理理
©  2016  IBM  Corporation
§ Javaヒープ
– Javaオブジェクトを格納する領領域
§ オブジェクト管理理
– Javaでは,不不要になったオブジェクトは
ガベージコレクタ(GC)が⾃自動回収する
§ オブジェクト管理理に関するトピック
– オブジェクトの構造
– オブジェクトの⽣生成
– オブジェクトの回収(GC)
– 関連する話題など
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁36
オブジェクト管理理
クラス管理
オブジェクト
管理
インタープリタ
JIT
コンパイラ
JITコンパイラ
生成コード
実行時
プロファイラ
クラスデータ
(Java  バイト
コード)
Javaヒープ
(Java  オブ
ジェクト)
Javaスタック
(ローカル変数,
オペランドスタック)
Java仮想マシン(Java  VM)
Java同期
ランタイム
Java例外処理
ランタイム
JVM
ランタイム
©  2016  IBM  Corporation
§ オブジェクト指向⾔言語では,オブジェクトを⽣生成しメソッドを呼び出すことで処理理が⾏行行われる
– オブジェクトはnewした時に「ヒープ」内に作られるが,ライブラリ内などで暗黙のうち
に⽣生成されるオブジェクトもたくさんある
§ ⾮非常に単純なプログラムの例例
– ⼀一⾒見見オブジェクトなど使っていないようでも,オブジェクトが使⽤用されている
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁37
オブジェクトを⽤用いた処理理
1  class  SayHello {
2          static  String  str =  "Hello  ";;
3
4   public  static  void  main(String[  ]  args)  {
5     String  msg =  str +  args[0];;
6     System.out.println(msg);;
7         msg =  null;;
8  } }
$  javac SayHello.java
$  java  SayHello world
Hello  world
StringBuilder tmp =  new  StringBuilder();;
tmp.append(str);;
tmp.append(args[0]);;
String  msg =  tmp.toString();;
§ ⾚赤字部分でオブジェクトが⽣生成される
§ オブジェクトの構造
– メタ情報が⼊入るヘッダ
– フィールド値が⼊入るボディ
String
value
offset=0
count=5
©  2016  IBM  Corporation
§ オブジェクトは,クラスで定義されたフィールドを持つ
– 親クラスのフィールドも持つので,親クラスのインスタンスのふりができる
§ フィールドを保持する「ボディ」の他に,メタ情報を持つ「ヘッダ」がある
– ヘッダには,クラスへのポインタ,配列列のサイズ,ロックやGCのための情報などがある
§ オブジェクトを指すには,直接指す⽅方法と,ハンドルを介す⽅方法がある
– ハンドルを介すとオブジェクトの移動がしやすいが,性能とメモリ消費に影響がある
– 現在の主流流は直接指す⽅方法
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁38
オブジェクトの構造
class  A  {
char  c;;
int i;;
short  s;;
}
i
s
j
a
c
s
ヘッダ
i
s c
ヘッダ
Aのインスタンス Bのインスタンス ハンドルテーブル
class  B  extends  A  {
int j;;
short  s;;
A  a;;
}
32bit
©  2016  IBM  Corporation
§ ハンドルの削除
– 最初はハンドルあり(低性能)+容易易なコンパクション
– →	
  ハンドルなし+保守的GCによる限定的コンパクション
– →	
  ハンドルなし+マップを⽤用意したtype	
  accurate	
  GC
§ ロックのためのデータ構造の⼯工夫
– 現在の同期機構では,ロックのためにヘッダ内の1ワード弱を使⽤用 [Bacon’98]
– あまり同期に使⽤用されないクラスはロックワードを持たない [Bacon’02]
§ 同期に使⽤用された場合は外部に追加データを⽤用意して対処
è 現在のIBM	
  Javaでは,ヘッダは最少1ワード(クラスポインタ+フラグのみ)
– 配列列の場合は,サイズを保持するために+1ワード
– 「頻繁に同期に使⽤用される」クラスの場合は+1ワード
§ Compressed	
  References
– 64bitマシンでも,ポインタを32bitに圧縮して保持
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁39
オブジェクト使⽤用メモリの削減
i
s
j
a
c
s
ヘッダ
i
s c
ヘッダ
Aのインスタンス Bのインスタンス ハンドルテーブル
32bit
©  2016  IBM  Corporation
§ オブジェクトを作る場所は,ヒープとしてメモリ空間上
に確保されている
– ヒープ上の,オブジェクトに割り当てていない場所を
フリーエリアやフリーリストとして管理理
– newが呼ばれると,フリーエリアからメモリを確保し
オブジェクトを作る
§ マルチスレッド環境への対処
– 複数のスレッドが同時にnewを呼ぶことがあるため,
ヒープからのオブジェクト領領域確保は排他的に⾏行行う必
要がある
– しかしそれだと遅くなるので,スレッドごとにヒープ
の⼀一部を割り当て(スレッドローカルヒープ),そこ
からオブジェクトを割り当てるのが⼀一般的
– スレッドローカルヒープがなくなった場合,新しいも
のをヒープから割り当てる(ここは排他制御が必要)
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁40
オブジェクトの⽣生成
Javaヒープ
For Th1 For Th2 For Th1
©  2016  IBM  Corporation
§ SayHelloクラスの初期化
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁41
オブジェクトを⽤用いた処理理
‘H’ ‘e’
‘l’ ‘l’
‘o’ ‘ ’
char[6]String
value
offset=0
count=6
str
class  SayHello
Javaヒープ
1  class  SayHello {
2      static  String  str =  "Hello  ";;
3
4      public  static  void  main(String[  ]  args)  {
5          String  msg =  str +  args[0];;
6          System.out.println(msg);;
7          msg =  null;;
8  }  }
Stringオブジェクトの
内部構造は処理理系依存
であり,ここで⽰示して
いるのは⼀一例例です.
©  2016  IBM  Corporation2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁42
オブジェクトを⽤用いた処理理
‘w’ ‘o’
‘r’ ‘l’
‘d’
char[5]
[0]
String[1]
String
value
offset=0
count=5
‘H’ ‘e’
‘l’ ‘l’
‘o’ ‘ ’
char[6]String
value
offset=0
count=6
str
args
class  SayHello
Thread  stack
Javaヒープ
1  class  SayHello {
2      static  String  str =  "Hello  ";;
3
4      public  static  void  main(String[  ]  args)  {
5          String  msg =  str +  args[0];;
6          System.out.println(msg);;
7          msg =  null;;
8  }  }
§ スレッドスタックと引数argの⽤用意
Stringオブジェクトの
内部構造は処理理系依存
であり,ここで⽰示して
いるのは⼀一例例です.
©  2016  IBM  Corporation
§ tmp =	
  new	
  StringBuilder();
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁43
オブジェクトを⽤用いた処理理
‘w’ ‘o’
‘r’ ‘l’
‘d’
char[5]
[0]
String[1]
String
value
offset=0
count=5
‘H’ ‘e’
‘l’ ‘l’
‘o’ ‘ ’
char[6]String
value
offset=0
count=6
‘H’ ‘e’
‘l’ ‘l’
‘o’ ‘ ’
char[16]
‘w’ ‘o’
‘r’ ‘l’
‘d’
StringBuilder
value
count=0
str
msg
args
tmp
class  SayHello
Thread  stack
Javaヒープ
1  class  SayHello {
2      static  String  str =  "Hello  ";;
3
4      public  static  void  main(String[  ]  args)  {
5          String  msg =  str +  args[0];;
6          System.out.println(msg);;
7          msg =  null;;
8  }  }
Stringオブジェクトの
内部構造は処理理系依存
であり,ここで⽰示して
いるのは⼀一例例です.
©  2016  IBM  Corporation
‘H’ ‘e’
‘l’ ‘l’
‘o’ ‘ ’
char[16]
‘w’ ‘o’
‘r’ ‘l’
‘d’
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁44
オブジェクトを⽤用いた処理理
‘w’ ‘o’
‘r’ ‘l’
‘d’
char[5]
[0]
String[1]
String
value
offset=0
count=5
‘H’ ‘e’
‘l’ ‘l’
‘o’ ‘ ’
char[6]String
value
offset=0
count=6
‘H’ ‘e’
‘l’ ‘l’
‘o’ ‘ ’
char[16]
‘w’ ‘o’
‘r’ ‘l’
‘d’
StringBuilder
value
count=11
str
msg
args
tmp
class  SayHello
Thread  stack
Javaヒープ
1  class  SayHello {
2      static  String  str =  "Hello  ";;
3
4      public  static  void  main(String[  ]  args)  {
5          String  msg =  str +  args[0];;
6          System.out.println(msg);;
7          msg =  null;;
8  }  }
§ tmp.append(str);	
  tmp.append(args[0]);
Stringオブジェクトの
内部構造は処理理系依存
であり,ここで⽰示して
いるのは⼀一例例です.
©  2016  IBM  Corporation
§ msg =	
  tmp.toString();
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁45
オブジェクトを⽤用いた処理理
‘w’ ‘o’
‘r’ ‘l’
‘d’
char[5]
[0]
String[1]
String
value
offset=0
count=5
‘H’ ‘e’
‘l’ ‘l’
‘o’ ‘ ’
char[6]String
value
offset=0
count=6
‘H’ ‘e’
‘l’ ‘l’
‘o’ ‘ ’
char[16]
‘w’ ‘o’
‘r’ ‘l’
‘d’
String
value
offset=0
count=11
StringBuilder
value
count=11
str
msg
args
tmp
class  SayHello
Thread  stack
Javaヒープ
1  class  SayHello {
2      static  String  str =  "Hello  ";;
3
4      public  static  void  main(String[  ]  args)  {
5          String  msg =  str +  args[0];;
6          System.out.println(msg);;
7          msg =  null;;
8  }  }
Stringオブジェクトの
内部構造は処理理系依存
であり,ここで⽰示して
いるのは⼀一例例です.
©  2016  IBM  Corporation
§ msg =	
  null;
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁46
オブジェクトを⽤用いた処理理
‘w’ ‘o’
‘r’ ‘l’
‘d’
char[5]
[0]
String[1]
String
value
offset=0
count=5
‘H’ ‘e’
‘l’ ‘l’
‘o’ ‘ ’
char[6]String
value
offset=0
count=6
‘H’ ‘e’
‘l’ ‘l’
‘o’ ‘ ’
char[16]
‘w’ ‘o’
‘r’ ‘l’
‘d’
String
value
offset=0
count=11
StringBuilder
value
count=11
str
msg
args
tmp
class  SayHello
Thread  stack
Javaヒープ
1  class  SayHello {
2      static  String  str =  "Hello  ";;
3
4      public  static  void  main(String[  ]  args)  {
5          String  msg =  str +  args[0];;
6          System.out.println(msg);;
7          msg =  null;;
8  }  }
Stringオブジェクトの
内部構造は処理理系依存
であり,ここで⽰示して
いるのは⼀一例例です.
©  2016  IBM  Corporation
§ オブジェクトは使われなくなってもヒープに残る!
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁47
オブジェクトを⽤用いた処理理
‘w’ ‘o’
‘r’ ‘l’
‘d’
char[5]
[0]
String[1]
String
value
offset=0
count=5
‘H’ ‘e’
‘l’ ‘l’
‘o’ ‘ ’
char[6]String
value
offset=0
count=6
‘H’ ‘e’
‘l’ ‘l’
‘o’ ‘ ’
char[16]
‘w’ ‘o’
‘r’ ‘l’
‘d’
String
value
offset=0
count=11
StringBuilder
value
count=11
str
msg
args
tmp
class  SayHello
Thread  stack
Javaヒープ
1  class  SayHello {
2      static  String  str =  "Hello  ";;
3
4      public  static  void  main(String[  ]  args)  {
5          String  msg =  str +  args[0];;
6          System.out.println(msg);;
7          msg =  null;;
8  }  }
Stringオブジェクトの
内部構造は処理理系依存
であり,ここで⽰示して
いるのは⼀一例例です.
©  2016  IBM  Corporation
§ ⽣生成したオブジェクトは,不不要になったら消去しなければならない
– そうしないと,ヒープがいっぱいになって処理理が続けられなくなる
§ C++では(デフォルトでは),deleteによりアプリが明⽰示的に消去する
– 消去し忘れや,不不要でないのに消去してしまうなどの危険性がある
– セキュリティーホールにもなりえる
§ Javaでは,ガベージコレクタ(GC)が標準装備されており,
不不要なオブジェクト(=ガベージ)は⾃自動的に回収(=コレクト)される
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁48
オブジェクトの回収
©  2016  IBM  Corporation2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁49
不不要なオブジェクトとは?
‘w’ ‘o’
‘r’ ‘l’
‘d’
char[5]
[0]
String[1]
String
value
offset=0
count=5
‘H’ ‘e’
‘l’ ‘l’
‘o’ ‘ ’
char[6]String
value
offset=0
count=6
str
msg
args
tmp
class  SayHello
Thread  stack
Javaヒープ
‘H’ ‘e’
‘l’ ‘l’
‘o’ ‘ ’
char[16]
‘w’ ‘o’
‘r’ ‘l’
‘d’
String
value
offset=0
count=11
StringBuilder
value
count=11
1  class  SayHello {
2      static  String  str =  "Hello  ";;
3
4      public  static  void  main(String[  ]  args)  {
5          String  msg =  str +  args[0];;
6          System.out.println(msg);;
7          msg =  null;;
8  }  }
§ GCルートからたどり着けないオブジェクトは不不要
7行目終了時点で
「死んで」いるオブジェクト
GCルートの例例
– スレッドの実⾏行行スタック
(ローカル変数)
– クラスのスタティック変数
(グローバル変数)
– などなど
©  2016  IBM  Corporation
§ ガベージコレクションの基本アルゴリズム(の⼀一つ)
1.	
  Stop	
  the	
  world
– すべてのスレッド(Mutator)を⼀一時停⽌止させる(Stop-­‐the-­‐world)
– GC中にオブジェクトの変更更を⾏行行わせないため
2.	
  Mark
– GCルートからたどれるオブジェクト
に「マーク」を付ける
– マークが付いたオブジェクトは
「⽣生きて」いる(=回収できない)
3.	
  Sweep
– マークが付いていないオブジェクト
の領領域をフリーリストにつなぐ
4.	
  後処理理
– 停⽌止したスレッドの実⾏行行を再開
§ 利利点:仕組みが単純
§ ⽋欠点:GC中,アプリケーションが停⽌止
してしまう,停⽌止時間も⻑⾧長め
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁50
ガベージコレクションの基本:Mark	
  &	
  Sweep
class SayHello
Thread stack
JavaヒープGCルート
M M M
M M
©  2016  IBM  Corporation
§ どのデータがオブジェクトを指しているの
か?
– たとえば,0x12345678というデータが
⼊入っていた場合,それはオブジェクト
を指しているのか,単なる⼤大きなint値
なのか?
§ 処理理系は,オブジェクトやクラスがどうい
う構造をしているのか知っている
(Javaでは)
– そのためGCは,オブジェクトを指す
フィールドだけをたどることができる
§ スレッドスタックの処理理が問題
– どのエントリがオブジェクトを指して
いるかがわからないといけない
– スレッド停⽌止地点によっても変わる
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁51
Mark処理理とその注意点
class SayHello
Thread stack
JavaヒープGCルート
M M M
M M
Mark処理
for (各GC Rootについて)
GC Root内のオブジェクト参照の場所を「処理リスト」に足す
while (処理リストに参照場所がある間) {
処理リストから参照場所を取り出す
参照先のオブジェクトがマーク済みなら次へ
オブジェクトをマークする
オブジェクト内の参照場所を処理リストに足す
}
©  2016  IBM  Corporation
§ スタックフレームのどこに「オブジェクトへの参照」が⼊入っているか?
– インタープリタ実⾏行行の場合は,Javaスタックのどのエントリがオブ
ジェクト参照であるかは(基本的に)わかるのでそれを使う
– JITコンパイルされたメソッドを実⾏行行している場合,ネイティブス
タックを使うので,簡単にわからないことがある.
§ さらに,CPUレジスタからオブジェクトを指している場合もある
§ スレッドを⼀一時停⽌止させる時,上の情報がわかるポイント
(GC	
  Safe	
  Point)でのみ停⽌止させる
– この時同時にCPUのレジスタの内容もメモリに書き出す
– 停⽌止した場所(プログラムカウンタ)から,スタックフレームのど
の場所にオブジェクト参照があるかの「マップ」を引き,マーク処
理理を⾏行行う
§ そのようなマップを⽤用意するのは処理理系(JITコンパイラ)の責任
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁52
スレッドスタックのスキャン
main
のスタック
フレーム
methodX
のスタック
フレーム
methodY
のスタック
フレーム
msg
args
tmp
ret
o
obj
arg
ret
a
b
tmp
ret
p
i
i
ある時点での
スタックの例
©  2016  IBM  Corporation
§ GC	
  Safe	
  Pointの⽤用意
– 他のメソッドを呼び出す(新しいスタックフレームができる)地点は
GC	
  Safe	
  Pointにしないといけない
– ループしている部分は,その中にGC	
  Safe	
  Pointがないといけない
§ 通常,ループのバックエッジ部分をGC	
  Safe	
  Pointにする
§ GC	
  Safe	
  Pointでスレッドを停⽌止するには?
– スレッド外から強制的に(pthread_killなどで)停⽌止させると,どこで停まるかわからない
– 協調的なスレッド停⽌止機構が必要
§ インタープリタやJITコンパイルされたコードは,GC	
  Safe	
  Pointの通過時にフラグを
チェックして,停⽌止を要求されている場合は⾃自主的に停まる
§ この時同時にCPUのレジスタの内容もメモリに書き出し,動作再開時にCPUのレジス
タに書き戻す
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁53
GC	
  Safe	
  Pointでのスレッド停⽌止
©  2016  IBM  Corporation
§ GC	
  Safe	
  Pointやマップが作れない場合の⽅方法
– ⾔言語処理理系の「助け」が不不要なGC⼿手法
– オブジェクトぽい値はオブジェクトを指していると考えて保守的にマークする
§ 「オブジェクトぽい」とは?
=値が,割り当て中のオブジェクトの(先頭)アドレスと⼀一致している
§ ヒープのアドレスや,各オブジェクトの先頭アドレスはわかるという前提
– 初期のJava処理理系はこれ(Conservative	
  GC)を使っていた
§ 逆に,型情報が完全にわかる最近のGCは「Type-­‐Accurate	
  GC」とも呼ばれる
§ 利利点:
– GC	
  Safe	
  Pointやマップを⽤用意しなくてもマーク処理理が⾏行行える
§ ⽋欠点:
– 不不要であるはずのオブジェクトまでマークしてしまう危険性がある
– 特に,使い終わったローカル変数などを積極的にクリアする必要がある
– 保守的にマークされたオブジェクトは動かすことができない
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁54
Conservative(保守的) Marking
©  2016  IBM  Corporation
§ マークが付かなかったオブジェクトの領領域を
フリーリストにつなぐ
– 同時に,次のGCのためにマークをクリアする
– 前後にフリー領領域がある場合は結合する(Coalescing)
§ マークをどこに置くか?
⽅方法1.	
  オブジェクトのヘッダに⼊入れる
⽅方法2.	
  別の場所にビット列列を⽤用意する
§ オブジェクトは8バイト単位でアラインされている
ことなどを利利⽤用して圧縮可能
§ ヒープ全体にアクセスが起こらないので,この⼿手法
が⼀一般的
§ Sweep処理理を繰り返すうちに,フリー領領域が細切切れになっ
てしまう危険性がある(Fragmentation)
àオブジェクトをヒープ内で詰めなおして
⼤大きな連続フリー領領域を作るCompactionが必要
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁55
Sweep処理理とその注意点
Javaヒープ
Sweep処理
for (割り当て中の各オブジェクト領域について) {
if (マークが付いている) マークをクリアして次へ
else {
領域をフリーリストにつなぐ(オブジェクトの回収)
その際,前後にフリー領域がある場合は結合する
} }
©  2016  IBM  Corporation
§ そのオブジェクトを指している参照をすべて移動先に書き換える必要がある
– Conservativeに指されているオブジェクトは動かせないので注意が必要
§ 参照元が本当にそのオブジェクトを指しているのか,ただの数値なのか判別がつかな
いため
§ Compactionの⼀一⼿手法(Forwarding	
  Pointer法)
1. まず,⽣生きているオブジェクトの「移動先」
を決め,各オブジェクトのForwarding	
  Pointer
に記録
2. 参照を「移動先」に書き換える
3. ⽣生きているオブジェクトを移動先に移動する
§ 利利点:Fragmentationの解消,使⽤用ヒープエリアの縮⼩小
§ ⽋欠点:複数回の追加ヒープスキャンが必要
– そのため,Compactionは毎回のGCでは⾏行行わないことが多い
– スキャンの少ないReverse	
  Pointer法などもある
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁56
Compaction処理理とその注意点
Compaction処理(Forwarding Pointer法)
for (生きている各オブジェクトについて)
移動先を決め,オブジェクトのForwarding Pointerに記録
for (GC Root内と生きている各オブジェクト内の参照について)
参照を「移動先」に書き換える
for (生きている各オブジェクトについて)
オブジェクトを移動先に移動する
©  2016  IBM  Corporation
§ 多くのオブジェクトの寿命は短い
– ⽣生成された後しばらく使われ,
すぐに不不要になる
à ヒープを「新世代オブジェクト⽤用の
領領域(nursery)」と「旧世代⽤用の領領域
(tenured)」に分ける
– 新世代領領域はCopying	
  GC,
旧世代領領域はMark	
  &	
  Sweep	
  GC
– Copying	
  GCを何回か⽣生き延びると,その
オブジェクトは旧世代領領域に移される
(Tenuring,殿堂⼊入り)
§ 旧世代から新世代を指す場合は,
Remembered	
  Setに追加する
§ 利利点:GCによる停⽌止時間が短い(頻繁に⾏行行われる新世代領領域のGCについて)
§ ⽋欠点:Write	
  Barrier処理理(旧世代から新世代を指してないかのチェック)
– スループットだけを考えるなら,単純なMark	
  &	
  Sweepの⽅方が⾼高い
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁57
その他のGC⼿手法:Generational	
  +	
  Copying	
  GC
class SayHello
Thread stack
Javaヒープ(nursery1)
GCルート
Javaヒープ(tenured)Remem-
bered Set
Javaヒープ(nursery2)
©  2016  IBM  Corporation
§ ヒープをたくさんの「リージョン」に分割して管理理
– 各リージョンを,nurseryやtenured領領域として割り当てることができる
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁58
その他のGC⼿手法:Region	
  Based	
  GC
Javaヒープ
未使用 Nursery
(新規割当用)
Nursery
(生き残った
オブジェクト)
Tenured
Nursery
(生き残った
オブジェクト)
Tenured
(巨大なオブ
ジェクト用)
Tenured 未使用
Tenured 未使用 未使用 未使用
©  2016  IBM  Corporation
§ 各オブジェクトについて,何箇所から指されているかのカウンタを管理理する
– カウンタがゼロになったら回収する
§ オブジェクト参照を変更更する処理理で,カウンタのアップダウン処理理が必要
– たとえば,x.a =	
  y	
  という処理理では,オブジェクトyのカウンタを+1し,x.aが元々指していた
オブジェクトzのカウンタを-­‐1する
– zのカウンタが0になったら回収し,zが
指しているオブジェクトのカウンタも-­‐1
§ 利利点:GCによる停⽌止時間がない
– 死んだオブジェクトはすぐ回収可能
§ ⽋欠点:
– カウンタ操作が重い
– すべてのオブジェクト書き込み
ポイントにカウンタ処理理が必要
§ 抜けがあるとヒープが壊れる
– 循環参照が回収できない
§ そのため通常,Mark	
  &	
  Sweep
と組み合わせて⽤用いられる
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁59
その他のGC⼿手法:Reference	
  Counting	
  GC
class SayHello
Thread stack
Java heapGC Root
1 1 1
0 0
1 1
01
1 12
©  2016  IBM  Corporation
§ Incremental	
  GC	
  (Concurrent	
  GC)
– Mutator(アプリの動作)と並⾏行行して,少しずつMark処理理を⾏行行う
– オブジェクトを3⾊色に塗る(Tri-­‐coloring)
§ ⽩白:まだチェックしていないオブジェクト
§ 灰:チェック途中のオブジェクト,⽩白を指してもよい
§ ⿊黒:チェック済みのオブジェクト,⽩白を指してはいけない
– 基本動作
§ まずすべてを⽩白にし,GCルートからたどれるものを灰⾊色にする
§ 灰⾊色の先を灰⾊色にする,全部灰⾊色になったらそのオブジェクトは⿊黒にできる
ここの処理理を「少しずつ」⾏行行える
§ 灰⾊色がなくなったら,⽩白のままのオブジェクトを回収して終わり
– ⿊黒から⽩白を参照するのを防ぐためにWrite	
  Barrierが必要
§ それが起きたら⿊黒オブジェクト(か⽩白)を灰⾊色にする
– 利利点:GCによる⼀一回の停⽌止時間を減らせる
§ Parallel	
   GC
– GC処理理(MarkやSweep)を,複数スレッドを⽤用いて並列列に⾏行行う
– 利利点:GC処理理の⾼高速化
… などなど
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁60
その他のGC⼿手法
©  2016  IBM  Corporation
§ IBM	
  Java
– Generational	
  +	
  Copying	
  
+	
  Concurrent	
  +	
  Parallel	
  (default)
– Parallel	
  Mark	
  &	
  Sweep
(-­‐Xgcpolicy:optthruput)
§ HotSpot VM	
  /	
  OpenJDK
– Parallel	
  +	
  Generational
– “G1	
  Collector”
§ Region-­‐Based	
  GC
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁61
各⾔言語実装のGC
§ C++	
  (Boehm	
  GCライブラリ)
– Conservative	
  Mark	
  &	
  Sweep
§ Ruby
– Conservative	
  Mark	
  &	
  Sweep
– “Restricted”	
  Generational	
  /	
  
Incremental	
  GC
§ C-­‐Python
– Reference	
  counting
§ PHP	
  (Zend)
– Reference	
  counting
§ Swift
– Reference	
  counting
©  2016  IBM  Corporation
GC関連の話題いろいろ
62 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁
©  2016  IBM  Corporation
§ ⼀一般に,⾔言語がその⾔言語以外で書かれた(ネイティブな)処理理を実⾏行行できる場合,オブジェ
クトを勝⼿手に操作されると正しいGCが困難になる
– たとえば,ネイティブコードでオブジェクトを変更更するとWrite	
  Barrierの処理理が⾏行行えない
– そもそも,ネイティブコードが使⽤用中のオブジェクトがわからないと回収してよいかも決
められない
§ Javaの場合,JNIインタフェースを使っていれば⼤大きな問題は⽣生じない
– オブジェクトに対する操作は,すべてJNIインタフェースを通じて⾏行行われる
§ GetObjectField(env,	
  obj,	
  fid),SetObjectField(env,	
  obj,	
  fid,	
  obj)	
  など
– オブジェクトのアドレスはネイティブコードには渡らない,「ハンドル」が渡される
§ そのようなオブジェクトは「表」に登録される,この表がGCルートとして扱われる
– 配列列や⽂文字列列の⾼高速操作のために,アドレスを直接渡す場合だけ注意が必要
§ GetPrimitiveArrayCritical(env,	
  array,	
  &isCopy)	
  は,Java配列列のアドレスをそのまま返せる
が,ReleaseするまではGC	
  unsafeになる
§ JITコンパイルされたネイティブコードの扱い
– JITコンパイラが,コンパイルしたコードにGC	
  Safe	
  Pointとマップを⽤用意する
– 同時に,スレッドをGC	
  Safe	
  Pointで停⽌止させる仕組みも必要
§ これらがない場合は,Conservative	
  GCになる
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁63
GC関連の話題:ネイティブコードへの対応
©  2016  IBM  Corporation
§ JavaにはString.intern()という処理理があり,同じ内容の⽂文字列列を⼀一つのオブジェクトにまとめる
ことができる(インターン処理理)
– 特に,リテラル⽂文字列列("Hello"	
  のようにプログラム中に直接書かれている⽂文字列列)は,
使⽤用時に⾃自動的にインターンされる
§ インターンされた⽂文字列列オブジェクトは,処理理系内部の「Intern	
  Table」に登録されている
– 同じ⽂文字列列に対してString.intern()が呼ばれた場合に,既存のインターン済みオブジェクト
にまとめるため
§ Intern	
  TableはGCルートではないが・・・
– インターンされた⽂文字列列オブジェクトが回収される場合,Intern	
  Tableから削除する処理理を
忘れず⾏行行わなければならない
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁64
GC関連の話題:String	
  Intern	
  Tableへの対応
©  2016  IBM  Corporation
§ Javaでは,オブジェクトが回収される時にfinalizeというメソッドを呼び出すことができる
§ GCではたとえば以下の処理理が必要
– Mark時に,finalizeメソッドを持つオブジェクトの先についてもMark処理理し,
– Sweep時に,finalizeメソッドを持つオブジェクトは解放せず,「Finalizationキュー」につ
なぐ
§ システム内の「Finalizerスレッド」が,キュー内のオブジェクトのfinalizeメソッドを順
に呼び出していく
§ finalize処理理により,オブジェクトが「⽣生き返る」こともある
※ finalizeメソッドが呼ばれるタイミングはすごく後になることもあるので,
あまり使うべきではない(メモリリークの原因にもなりえる)
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁65
GC関連の話題:Finalizerへの対応
©  2016  IBM  Corporation
§ Javaでは,オブジェクトを「弱く参照(Weak	
  Reference)」することができる
– 弱参照しかされていないオブジェクトはGCの対象になる
– WeakHashMapなどで利利⽤用
§ キーを弱参照で保持,キーが回収されるとHashMapからも消される
– 弱参照は,WeakReferenceという特別なオブジェクトを通じて⾏行行う
§ 弱参照先が回収されると,ReferenceQueueに⼊入れられる
§ GCでは,GC後にWeakReferenceオブジェクトだけを再チェックし,
弱参照先が回収されていたらキューにつなぐ,などの⽅方式で実装できる
– もしくは,マークに「⾊色」をつける(StrongなマークとWeakなマーク)など
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁66
GC関連の話題:Weak	
  Referenceへの対応
©  2016  IBM  Corporation
§ 特定の条件を満たすオブジェクトは,ヒープでなく
スタック上に作ることも可能
– newしたメソッド内(以下)でしか使われない
– 他のオブジェクトなどに代⼊入されない
– これらの条件を満たすオブジェクトは
メソッドから「Escapeしていない」と⾔言う
§ JITコンパイラが「Escape	
  Analysis」を⾏行行い,
スタック上にオブジェクトを⽣生成するコードを出すことも可能
– スタックアロケートされたオブジェクトは,メソッド終了了時(スタックフレーム解放時)
に⾃自動的に回収できる
– ただしGC側でも,スタック上のオブジェクトを移動しないようにするなどの対応が必要
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁67
GC関連の話題:スタック上へのオブジェクト配置
String  concat(String  a,  String  b)  {
StringBuilder  sb  =  new  StringBuilder();;
sb.append(a);;  sb.append(b);;
return  sb.toString();;
}
上のStringBuilderオブジェクトはconcatメソッ
ドからEscapeしていないので,(処理系がが
んばれば)スタック上に配置することが可能
©  2016  IBM  Corporation
§ Javaアプリの性能が出ない場合,GCログをチェックするのが分析の第⼀一歩
§ GC頻発の様々な要因(oはGC発⽣生地点)
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁68
GCログからの問題分析
(a)  健全な状態 (b)  長期オブジェクトが多すぎる
(c)  メモリー・リーク (d)  短期オブジェクトができすぎる
GC後のヒープ使用量
時間経過
最大ヒープ・サイズ
GC発生ポイント
©  2016  IBM  Corporation
§ GCログを可視化し分析すると,たとえば以下のようなことがわかる
– ヒープサイズは◯GBぐらい,Nurseryは◯GBぐらい
– Minor	
  GCは◯秒に1回ぐらいのペースで起きている.つまり◯秒で◯GBぐらいアロケート
している,毎分◯GBのペース
– Minor	
  GCごとにちょっとずつオブジェクトがTenured領領域に逃げて⾏行行き,Major	
  GCを引き
起こしている
– Major	
  GCが起きても回収できないものが少しずつ積みあがっていく(要するに何かがメモ
リリークしている)
– ヒープ使⽤用量量が少し下がるところ(最初以外)はcompactionが起きている,この
compactionに◯秒ぐらいかかったあげく回収できるのがたった◯MBぐらい
– Major	
  GCの頻度度はヒープが狭くなるとどんどん上がり,最終的には◯分に1回ぐらいに
なっている
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁69
GCログからの問題分析:実例例
©  2016  IBM  Corporation
Java:	
  IBM	
  J9	
  Java	
  VM	
  6.0	
  SR7	
  32bit
HW:	
  Dual-­‐core	
  Opteron	
  2.4GHz	
  x2,	
  4GB	
  Memory
OS:	
  SUSE	
  Linux	
  Enterprise	
  Server	
  10.0
§ Java処理理系は,ヒープ以外にも意外とメモリを消費している
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁70
メモリの話題:ヒープ以外のメモリ消費 [Ogata’10]
0 50 100 150 200 250MB
Malloc-­then-­freed  
area=37MB
Non-­Java  
memory  
size  by  
category
M.M.  overhead=6MB
DLL=8MB
JVM  work  area=42MB
Class  area=87MB
JITed  code=10MB
JIT  work  area=18  MB
Stack=4MB
Java  heap
253MB
+
©  2016  IBM  Corporation
§ Javaアプリでは,⽣生成されるオブジェクトの⼤大部分がStringオブジェクト
– Stringオブジェクト内に,GCでは回収できないメモリの無駄がある
§ ライブヒープの40%は⽂文字列列保持のために⽤用いられているが,そのうち50%は無駄な領領域
– 25%	
  は重複した⽂文字列列
– 1%	
  はchar配列列内の使⽤用されない領領域
– 24%	
  は使⽤用されないリテラルデータ
§ これらはオブジェクト内の無駄なので従来のGCでは除去できない
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁71
メモリの話題:String⽤用メモリの無駄 [Kawachiya’08]
0 5 10 15 20 25 30
Trade6
MB
dup
unused literals
String char[ ] other objects
String memory inefficiencies (~20% of live heap)
Live  heap  
breakdown
of  Trade6
Java:	
  IBM	
  J9	
  Java	
  VM	
  5.0	
  for	
  Linux
App:	
  Trade6	
  benchmark	
  on	
  IBM	
  WAS	
  6.1
HW:	
  Xeon	
  3.06GHz	
  x2,	
  4GB	
  Memory
OS:	
  Red	
  Hat	
  Enterprise	
  Linux	
  3	
  AS
スレッドと同期
©  2016  IBM  Corporation
§ Javaは,⾔言語⾃自体がスレッドによる並列列処理理を
サポートしている
§ Java処理理系には,スレッド管理理のための仕組み
に加え,スレッド間の排他制御を⾏行行うための
同期機構が必要
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁73
スレッドと同期
クラス管理
オブジェクト
管理
インタープリタ
JIT
コンパイラ
JITコンパイラ
生成コード
実行時
プロファイラ
クラスデータ
(Java  バイト
コード)
Javaヒープ
(Java  オブ
ジェクト)
Javaスタック
(ローカル変数,
オペランドスタック)
Java仮想マシン(Java  VM)
Java同期
ランタイム
Java例外処理
ランタイム
JVM
ランタイム
©  2016  IBM  Corporation
§ Javaは⾔言語としてスレッドによる並列列処理理をサポートしている
– java.lang.Thread – スレッドを作成する標準クラス
– java.lang.Runnable – スレッドの処理理内容を記述するインタフェース
§ 商⽤用Java処理理系では,JavaスレッドはOSが提供するスレッド(たとえばpthread)
にマッピングされ,OS⾃自⾝身によってスケジュールされることが多い
– ネイティブメソッドからCコードやシステムコールを呼ぶ場合の親和性のため
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁74
スレッド処理理
class  MyRunnable implements  Runnable  {
static  MyCounter c  =  new  MyCounter();;
public  void  run()  {
System.out.println("Hello  "  +  c.add(1));;
}
}
Thread  t  =  new  Thread(new  MyRunnable());;
t.start();;  // スレッドを実行開始
Java  thread
JVM  thread
(C/C++)
pthread
©  2016  IBM  Corporation
Javaは,⾔言語⾃自体がスレッドによる並列列処理理をサポートしている
§ スレッド間の同期はsynchronizedメソッドなどで指定される
§ モニタ⽅方式の排他制御
– たかだか1つのスレッドだけが当該オブジェクトのsynchronizedメソッドを実⾏行行できる
– オブジェクトのロックが実⾏行行前に獲得され,実⾏行行後に解放される
– ロックの再帰獲得や,イベント待ち合わせ(wait)と通知(notify)も可能
§ Javaでは,以下の理理由によりロック処理理が頻繁に⾏行行われる
– ライブラリは「スレッドセーフ」に作らなければならない
– プログラマが容易易にロック処理理を指定できる (「synchronized」をつけるだけ)
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁75
Javaロック:スレッド間の同期機構
class  MyCounter {
int value  =  0;;
synchronized int add(int i)  {
value  =  value  +  i;;
return  value;;
}      }
MyCounter c1
add(1)
add(1)
add(1)
value:10
MyCounter c2
value:5
Thread A
Thread B
Thread C
©  2016  IBM  Corporation
§ 背景:Java⾔言語の浸透
– 現在ではC,C++とならぶポピュラーな⾔言語
– サーバー環境では,ウェブサービス構築の必須⾔言語
– クライアント環境でも,Eclipseなどで不不可⽋欠
§ 初期のJava⾔言語は処理理が⾮非常に遅かった・・・
– 機種独⽴立立なバイトコードを,Java仮想マシン(JVM)が実⾏行行する形式
à JITコンパイル技術の進歩により改善
– ランタイムシステムのオーバーヘッド
à こちらは,JITによる⾼高速化が難しい
§ 初期の処理理系では,実⾏行行時間の2割近くを
スレッド同期(ロック処理理)が占めていた
à Javaアプリケーションの⾼高速実⾏行行に,
ロック処理理の⾼高速化は不不可⽋欠
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁76
Javaロック⾼高速化の必要性
From  http://www.javaworld.com/jw-­03-­1998/jw-­03-­hotspot.html
©  2016  IBM  Corporation
§ Javaでは,ロックはオブジェクトを指定して⾏行行われる
à 各オブジェクトヘッダにモニタ構造体を⽤用意する
§ 当然のことながら,メモリ使⽤用効率率率が悪い
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁77
Javaロックの超ナイーブな実装
Object 1
Header
Body
Monitor
structure
Object 2
Header
Body
Monitor
structure
Object 3
Header
Body
Monitor
structure
Object 4
Header
Body
Monitor
structure
Object 5
Header
Body
Monitor
structure
typedef struct object  {
monitor_tmon;;  
:
}  Object;;
int Java_lock_acquire(Object  *obj) {  return  monitor_enter(&obj-­>mon);;  }
int Java_lock_release(Object  *obj) {  return  monitor_exit(&obj-­>mon);;  }
int Java_lock_wait(Object  *obj) {  return  monitor_wait(&obj-­>mon);;  }
int Java_lock_notify(Object  *obj) {  return  monitor_notify(&obj-­>mon);;  }
int Java_lock_notify_all(Object  *obj){  return  monitor_notify_all(&obj-­>mon);;  }
Javaロックの実装とは,
これらのデータ構造と
関数を用意すること
©  2016  IBM  Corporation
§ 実際には,⼀一部のオブジェクト(せいぜい1割)しかロック処理理に⽤用いられないことを利利⽤用
à オブジェクトとモニタ構造体の関連付けをグローバルな表で管理理
§ メモリ使⽤用効率率率は改善されたが,
モニタ表の更更新・参照のためにグローバルロックが必要,スケーラビリティ低下
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁78
「モニタ表」を⽤用いたJavaロック実装
Object 1
Header
Body
Monitor table
Object 2
Header
Body
Monitor
structure
Object 3
Header
Body(no field for lock)
Object 4
Header
Body
Object 5
Object 3
Monitor
structure
Object 5
Header
Body
Object 2
Monitor
structure
int Java_lock_acquire(Object  *obj)  {
monitor_t*mon  =  lookup_monitor(obj);;
return  monitor_enter(mon);;
}
int Java_lock_release(Object  *obj)  {
monitor_t*mon  =  lookup_monitor(obj);;
return  monitor_exit(mon);;
}
©  2016  IBM  Corporation
§ オブジェクトヘッダ内の,あまり使⽤用されないフィールドの利利⽤用
à ロックに使⽤用された場合,そのフィールドから直接モニタ構造体を指す
§ 元々あったデータは,モニタ構造体の中に移動する
§ スケーラビリティは改善されたが,
OSのモニタ機構をそのまま使っているため,依然として⾼高オーバーヘッド
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁79
Direct	
  Pointing⽅方式 [Onodera’98]
Object 2
Header
Body
Object 4
Header
Body
rarely-used info
0
Object 1
Header
Body
rarely-used info
0
Monitor
structure
Object 3
Header
Body
1
rarely-used info
Monitor
structure
rarely-used info
OBJFLAG_MON
_ASSOCIATED
Displaced info
Object 5
Header
Body
1
rarely-used info
Monitor
structure
1
©  2016  IBM  Corporation
§ Javaでは,多くのロックは衝突(contention)していないことを発⾒見見し活⽤用
à オブジェクトヘッダ内のロックワードを2つのモードで使⽤用する,bi-­‐modalロック
§ ロックが衝突するまでは,compare_and_swapでロック処理理を⾏行行う(Flatモード)
§ ロック衝突時にモニタ構造体を⽤用意し,以後はそれで処理理を⾏行行う(Inflatedモード)
– 2つのモードは,ロックワード内のShapeビットにより区別される
§ 多くのロック処理理で重いモニタ機構が不不要になり,
Javaアプリケーションの処理理性能が劇的に向上(元論論⽂文によれば「最⼤大1.7倍」)
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁80
Thinロック [Bacon’98	
  (Best	
  of	
  PLDI)]
Object 2
Header
Body
Object 3
Header
Body
Object 4
Header
Body
Object 1
Header
Body
Lockword
0
1
0
0
T
0
0
Monitor
structure
Shape bit
Object 5
Header
Body
1
Monitor
structure
int Java_lock_acquire(Object  *obj)  {
if  (compare_and_swap(&obj-­>lockword,  
0,  thread_id())  ==  SUCCESS)
return  SUCCESS;;
:
©  2016  IBM  Corporation
Javaロックのさらなる⾼高速化
81 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁
©  2016  IBM  Corporation
§ Thinロックにおけるロックワードの状態遷移
– compare_and_swap命令令1つでロック獲得,単純なストア命令令でロック解放が可能
§ モード遷移に関する2つの(潜在的な)問題
– インフレーション(FlatモードからInflatedモードへの遷移)にビジーウェイトを使⽤用
– デフレーションが無い.⼀一旦衝突が起きたロックは,以後Inflatedモードで処理理される
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁82
Thinロックの(潜在的な)問題点
Object 1
Header
Body
Lockword
0 0
T0
1
00
releaseacquire
Shape bit
Monitor
structure
inflate
Flat mode
(Shape bit=0)
Inflated mode
(Shape bit=1)
Object creation
(pointer)
Acquired by T
Not acquired
acquire / release
©  2016  IBM  Corporation
§ 各オブジェクトのロック衝突状況を,以下の指標を⽤用いて調査する
– Flatセクション―	
  ロックが衝突していない状態
– Fatセクション ―	
  ロック獲得(もしくはイベント通知)を待っているスレッドがいる状態
§ 結果:イベント待ち合わせに使われていないオブジェクトでは,衝突は⼀一時的な現象である
– Javaロックの「衝突の⼀一時性」,要するにObject	
  3のようなケースが多い
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁83
Javaロックの衝突に関する挙動調査
Created
Garbage
collected
Object 1
Created
Garbage
collected
Object 2
Created
Garbage
collected
Object 3
Flatセクション(ロックが衝突していない)
Fatセクション
(ロック獲得またはイベント通知を待っているスレッドがいる)
Time
©  2016  IBM  Corporation
§ たすきロックにおけるロックワードの状態遷移
§ デフレーションのサポート( 「衝突の⼀一時性」の活⽤用)
– 衝突が解消すると,ロックワードをFlatモードに戻す
§ インフレーション制御のために,オブジェクトヘッダに1ビットのフラグを追加
– FLC(Flat	
  Lock	
  Contention)ビット ―	
  Flatモードでのロック衝突を⽰示す
– ビジーウェイトを排除
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁84
たすきロック [Onodera’99]
T0
1
00
releaseacquire
Shape bit
Monitor
structure
Flat mode
(Shape bit=0)
Inflated mode
(Shape bit=1)
Object creation
(pointer)
Acquired by T
Not acquired
acquire / release
deflate & release
inflate
Object
Body
Shape bit FLC bit
Header
0 T
0
©  2016  IBM  Corporation
1 2 3 4 5 6 7 8 9 10
# Terminals
0
5
10
15
Throughput (x1000 tpm)
IBM116
Ours
+11.4%
+8.29%
+13.1%
+8.27%
§ Ibenchベンチマーク
– トランザクション処理理をエミュレート,ターミナル数 m	
  を変えて測定する
§ たすきロックにより最⼤大13.1%の性能向上を確認
– さらに,マルチスレッド環境での性能低下を抑制
– ロック処理理の98%以上がFlatモードで⾏行行えている(Thinロックでは74%)
Thin  lock
Tasuki
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁85
実アプリでの性能⽐比較
遅い←                                →  速い
IBM  JDK  1.1.6(Thinロックが採
用されている)に,たすきロックを
実装して測定した結果
たすきロック
Thinロック
Java	
  IBM	
  JDK	
  1.1.6
App:	
  Ibench benchmark
HW:	
  PowerPC	
  604ev	
  166MHz,	
  128MB	
  Memory
OS:	
  AIX	
  4.1.5
©  2016  IBM  Corporation
§ たすきロックにより,衝突がない状況ではわずか数命令令でロック処理理が可能になった
§ しかし,compare_and_swapなどの不不可分命令令が依然として必要
– 他者のJavaロック⼿手法でも同様の状況
– 不不可分命令令は⾮非常に重い命令令である
à ロックのfastest	
  pathから,不不可分命令令をなくせないか?
§ たとえば・・・
オブジェクトが特定のスレッドによってのみ頻繁にロックされているなら,
そのスレッドのロック処理理に限り不不可分命令令を無くせないか?
―	
  Javaロックの「スレッド局所性」
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁86
さらなる⾼高速化の可能性は?
オブジェクト
ヘッダ部
ボディ部
0 tid rcnt
ロックワード
compare_and_swapで
スレッドIDを書き込む
ことで,ロックを獲得
生成 消滅C C C C C BC CC
スレッドCがロック
スレッドCが頻繁にロックしている
オブジェ
クト
©  2016  IBM  Corporation
§ Javaロックの「スレッド局所性」を活⽤用
– オブジェクトを最初にロックしたスレッドが,ロックを「予約」できる
à そのスレッドが引き続きロックを⾏行行った場合のコストを下げられる
§ 予約ロックにおけるロック獲得処理理
1. そのスレッドが予約を持っていた場合,不不可分命令令なしの⾼高速処理理を⾏行行う
2. 他のスレッドが予約を持っていた場合,まずその予約を「解除」する
3. 予約がすでに解除されていた場合,従来の⽅方式(たとえば たすきロック)で処理理を⾏行行う
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁87
予約ロック [Kawachiya’02]
1. この部分が高速化される
生成 消滅
オブジェ
クト C C C C C BC CC
0. スレッドCに予約が与えられる
2. 予約が解除される
3. この部分は従来方式で処理される
©  2016  IBM  Corporation
1T 0
Reserved for Thread T
0 0
Anonymously reserved
Acquired by T
unreserve
acquire release
acquire release
1
Object creation
1T 1
1T 2
unreserve
unreserve
0
0
0
:
:
Base lock algorithm
Recursively acquired
:
:
Reserve mode
(LRV=1)
Base mode
(LRV=0)
xxxxxx
yyyyyy
zzzzzz
acquire
(initial synchronization)
LRV bit
§ ロックワードの状態遷移
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁88
予約ロックの動作 tid rcnt
LRVビット
1
再帰カウンタ
スレッドID
§ 予約スレッドは,rcntフィー
ルドを単純に増減することで
ロックの獲得と解放が⾏行行える
(不不可分命令令は不不要)
§ 別のスレッドがロック獲得
を試みた時点で,予約は
「解除」される
§ 解除後は,従来⼿手法により
処理理が⾏行行われる
– 複雑なケースはすべて
従来⼿手法に任せられる
©  2016  IBM  Corporation
§ 予約ロックでは,予約解除のコストが⾼高かった
– 予約を保持しているスレッドを外部から強制停⽌止させる必要があるため
– さらに,停⽌止した地点がロック処理理中(unsafe	
  region)であった場合,再開地点を移動す
る必要もあった
à 協調的スレッドスケジューリングを利利⽤用した改善
– スレッドを「GC	
  Safe	
  Point」で停⽌止させる仕組みを,予約解除時のスレッド停⽌止にも利利⽤用
メリット1. 予約解除の際の予約スレッド停⽌止にシステムコールが不不要であるため軽い
メリット2. unsafe	
  regionで停⽌止することがないので停⽌止後コンテクストをチェックする
必要がない
メリット3. 予約解除のコストが低いので,予約解除の頻度度等に応じて再予約も⾏行行える
メリット4. synchronizedセクション内にGC	
  safe	
  pointがない場合は,予約時のロック処理理
から再帰カウンタの上げ下げすら省省略略できる
§ IBM	
  Javaでは,-­‐XlockReservation オプションで使⽤用可能
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁89
改良良版予約ロック [Grcevski’07]
©  2016  IBM  Corporation
§ Apache	
  Sparkでの性能改善
– TPC-­‐Hを実⾏行行した場合,22のうち7つのQueryで10%以上の改善(最⼤大18%)
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁90
予約ロック(改良良版)の効果
出典: http://www.spark.tc/reserve-­locks-­spark-­performance
Java:	
  IBM	
  J9	
  Java	
  VM	
  Version	
  8	
  SR1	
  FP10
App:	
  TPC-­‐H	
  with	
  Spark	
  SQL	
  on	
  Spark	
  1.4.1,	
  with	
  100GB	
  dataset
HW:	
  POWER8	
  3.3GHz	
  x2	
  (total	
  24cores),	
  1TB	
  Memory
OS:	
  Ubuntu	
  Linux	
  14.10
©  2016  IBM  Corporation
§ Escape Analysisの活⽤用 [Whaley’99など]
– あるスレッドで⽣生成したオブジェクトが,そのスレッド以外には⾒見見えないことを解析する
– Escapeしていないオブジェクトは,スタック上に配置したり,ロック処理理を省省略略できる
§ Transactional	
  Memory的⼿手法の活⽤用 [Nakaike’10][Odaira’14]
– スレッドは全員synchronizedセクションを投機的に実⾏行行できる
– synchronizedセクションを抜けるときに,変更更内容をメモリに書き戻す
§ ただし,競合があった場合はやりなおしになる
§ いずれも,JITコンパイラなどによるコード解析が必要
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁91
その他の改善⼿手法:ロック除去
例例外処理理
©  2016  IBM  Corporation
§ 例例外の処理理
§ 例例外処理理のコスト
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁93
例例外処理理
クラス管理
オブジェクト
管理
インタープリタ
JIT
コンパイラ
JITコンパイラ
生成コード
実行時
プロファイラ
クラスデータ
(Java  バイト
コード)
Javaヒープ
(Java  オブ
ジェクト)
Javaスタック
(ローカル変数,
オペランドスタック)
Java仮想マシン(Java  VM)
Java同期
ランタイム
Java例外処理
ランタイム
JVM
ランタイム
©  2016  IBM  Corporation
§ try-­‐catch
– tryブロックのコード範囲でthrowされた例例外に対し,catchブロック(例例外ハンドラ)を
定義する構⽂文
– 各catchブロックは、指定する例例外クラス(およびその⼦子クラス)の例例外を処理理する
– finallyは,tryブロックの終了了時に必ず実⾏行行される
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁94
例例外の基本動作
try {
canThrowE1();;  //  例外E1を投げるかもしれないメソッド
}  catch (E1  e)  {
//  例外E1が起きた時のハンドラ
}  catch (E2  e)  {
//  例外E2が起きた時のハンドラ
}  finally {
//  tryブロック終了時に(例外の有無にかかわらず)実行するコード
}
©  2016  IBM  Corporation
§ バイトコードに「例例外表」がついている
– 「 [0,3)の範囲で例例外E1が起きた場合,
6へ⾶飛ぶ 」 à
§ 例例外が発⽣生すると,
– 例例外表をチェックし,ハンドラがあればそこへジャンプ
– ハンドラがなければ,スタックを⼀一段巻き戻し,同様の処理理を⾏行行う
§ synchronizedブロックでロックを取得している場合,javacがfinally節相当のエントリを⽣生成し
その中でアンロック(monitorexit)処理理を⾏行行うので,ランタイムでは特別な対処は不不要
– synchronizedメソッドの場合は,スタック巻き戻し時にランタイムがアンロックを⾏行行う
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁95
例例外の処理理
try {
canThrowE1();;
}  catch (E1  e)  {
//例外E1が起きた時のハンドラ
}
Code:
0:  invokestatic #4  //  Method  canThrowE1
3:  goto 7
6:  astore_0
7:  return
Exception  table:
from        to    target   type
0          3          6       Class  E1
©  2016  IBM  Corporation
§ 例例外表を内側からチェックする
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁96
ネストしたtry-­‐catch
try  {
m1();;
try  {
m2();;
try  {
m3();;
}  catch  (E3  e)  {
_m3();;
}
}  catch  (E2  e)  {
_m2();;
}
}  catch  (E1  e)  {
_m1();;
}
Exception  table:
from        to    target type
6          9       12 Class  E3
3        16        19 Class  E2
0        23        26 Class  E1
©  2016  IBM  Corporation
1. 例例外オブジェクトのnew
2. 例例外オブジェクトの<init>の呼出し
– コールスタックの記録オブジェクトのnew
– コールスタックのトレース
3. 例例外をthrow
4. 例例外ハンドラのサーチ
– コールスタックの巻き戻し
– 各フレームから例例外表を取得
– 例例外表で,プログラムカウンタに該当するtryを識識別
– tryにひもづいた例例外ハンドラの各候補に対し、現在の例例外クラスを扱えるかテスト
(instanceofと同等の処理理)
5. 例例外ハンドラから実⾏行行を再開
à改善策:プロファイリングでthrowとcatchのペアを⾒見見つけ,
JITコンパイル時に処理理してしまう [Ogasawara’01]
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁97
例例外処理理のコストと改良良
JITコンパイラ
©  2016  IBM  Corporation
§ バイトコードを実⾏行行時(Just-­‐In-­‐Time)にコン
パイルし,⾼高速実⾏行行する
– 実⾏行行時プロファイラを⽤用いて,JITコンパイ
ラによる最適化に有益な情報を収集するこ
とも可能
§ インタープリタの役割
– どのメソッドをJITをコンパイルするか決定
– JIT前にシンボルの解決(Resolve)などを
なるべく済ませる
– プロファイリング,統計情報収集など
§ 詳細はこの次の講演にて
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁99
JITコンパイラ(さわりだけ)
クラス管理
オブジェクト
管理
インタープリタ
JIT
コンパイラ
JITコンパイラ
生成コード
実行時
プロファイラ
クラスデータ
(Java  バイト
コード)
Javaヒープ
(Java  オブ
ジェクト)
Javaスタック
(ローカル変数,
オペランドスタック)
Java仮想マシン(Java  VM)
Java同期
ランタイム
Java例外処理
ランタイム
JVM
ランタイム
©  2016  IBM  Corporation
§ Javaバイトコードが実⾏行行される時に,そのバイトコードをコンパイルするコンパイラ
– ⼀一般的には,メソッド単位(+インライニング)でコンパイルを⾏行行う
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁100
Java	
  Just-­‐in-­‐Time	
  (JIT)コンパイラ
public  class  Hello  {
public  static  void  main(String[]  args)  {
System.out.println("Hello");;
…
Hello.java
(ソースコード)
public  static  void  main(java.lang.String[]);;
Code:
0:  getstatic
3:  ldc
…
Hello.class
(バイトコード)
javac Hello.java(実⾏行行前に⾏行行う)
main:
ld
st
…
ネイティブコード
(マシンコード)
JITコンパイル(実⾏行行中に⾏行行う)
これはJITでは
ないので注意
Java仮想マシン
の守備範囲
©  2016  IBM  Corporation
§ バイトコードのポータビリティ(Write	
  Once	
  Run	
  Anywhere)維持のため
– 実⾏行行時に各プラットフォーム向けのバイナリを⽣生成
§ 実⾏行行時(プロファイル)情報を最適化に使うため
– メソッドの呼び出し頻度度等
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁101
なぜJIT(実⾏行行中に)コンパイルするのか?
public  class  A  {
public  void foo()  {…}
}
public  class  B  extends  A  {
public  void  foo()  {…}
}
public  class  C  extends  A  {
public  void  foo()  {…}
}
public  void  bar  (A  a)  {
…
a.foo();;
…
}
クラスA,  B,  Cの3つのfooメソッドが呼び
出される可能性があるが,頻繁に呼び出
されるメソッドをインラインしたい
©  2016  IBM  Corporation
JITコンパイルの⼿手順
102 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁
public void foo()
Code:
0: getstatic
3: ldc
…
public void bar()
Code:
0: getstatic
3: ldc
…
public void zoo()
Code:
0: getstatic
3: ldc
…
インタープリタ
1.  最初はバイトコードをインタープリタ実⾏行行
JITコンパイラ
foo:
ld
st
…
bar:
ld
st
…
zoo:
ld
st
…
2.  呼び出し回数が閾値を越えたメソッド
に対してJITコンパイルリクエスト
3.  バイナリコードを⽣生成しプロセッサ上で直接実⾏行行
©  2016  IBM  Corporation
§ 各メソッドの性能に与える影響(=全実⾏行行時間に占める割合,method	
  hotness)に応じて
最適化レベルを変更更
– よく使われるメソッドは,より時間をかけて⾼高度度に最適化する
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁103
適応的コンパイル(Adaptive	
  Compilation)
インタープリタ実行
低最適化レベルでのコンパイル
実行時間のプロファイル
高最適化レベルでのコンパイル
§ IBM	
  Java	
  JITコンパイラは6段の最適化
レベルを使⽤用
scorching
veryHot
hot
warm  (最初の最適化レベル)
cold
noOpt
高
低
©  2016  IBM  Corporation
§ メソッドを定期的にサンプリング
– サンプリングスレッドが定期的にアプリケーションスレッドの「フラグ」をセット
– アプリケーションスレッドは,フラグがセットされたときに実⾏行行していたメソッドを
サンプリング
§ フラグチェックは,GC	
  Safe	
  Pointで⾏行行う
– メソッドの⼊入り⼝口,メソッドの出⼝口,ループの最後など
– もともとGCのために⽤用意されているため,オーバヘッドにならない
2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁104
メソッドの実⾏行行時間のプロファイル
サンプリングスレッド
サンプリングインターバル(e.g.  10ms)
アプリケーションスレッド1
アプリケーションスレッド2
フラグセット メソッドAを実行
samples(A)++
メソッドBを実行
samples(B)++
public  void  foo()  {
check();;
for  (…)  {
s  +=  a[i];;
check();;
}
check();;
}
まとめ
Java仮想マシンの実装技術

Más contenido relacionado

La actualidad más candente

Akkaとは。アクターモデル とは。
Akkaとは。アクターモデル とは。Akkaとは。アクターモデル とは。
Akkaとは。アクターモデル とは。Kenjiro Kubota
 
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?kwatch
 
最適なOpenJDKディストリビューションの選び方 #codetokyo19B3 #ccc_l5
最適なOpenJDKディストリビューションの選び方 #codetokyo19B3 #ccc_l5最適なOpenJDKディストリビューションの選び方 #codetokyo19B3 #ccc_l5
最適なOpenJDKディストリビューションの選び方 #codetokyo19B3 #ccc_l5Takahiro YAMADA
 
jcmd をさわってみよう
jcmd をさわってみようjcmd をさわってみよう
jcmd をさわってみようTsunenaga Hanyuda
 
Java 9で進化する診断ツール
Java 9で進化する診断ツールJava 9で進化する診断ツール
Java 9で進化する診断ツールYasumasa Suenaga
 
デキるプログラマだけが知っているコードレビュー7つの秘訣
デキるプログラマだけが知っているコードレビュー7つの秘訣デキるプログラマだけが知っているコードレビュー7つの秘訣
デキるプログラマだけが知っているコードレビュー7つの秘訣Masahiro Nishimi
 
O/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐO/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐkwatch
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪Takuto Wada
 
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...NTT DATA Technology & Innovation
 
Unified JVM Logging
Unified JVM LoggingUnified JVM Logging
Unified JVM LoggingYuji Kubota
 
java.lang.OutOfMemoryError #渋谷java
java.lang.OutOfMemoryError #渋谷javajava.lang.OutOfMemoryError #渋谷java
java.lang.OutOfMemoryError #渋谷javaYuji Kubota
 
ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方増田 亨
 
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~Daisuke Morishita
 
SQL大量発行処理をいかにして高速化するか
SQL大量発行処理をいかにして高速化するかSQL大量発行処理をいかにして高速化するか
SQL大量発行処理をいかにして高速化するかShogo Wakayama
 
Java によるクラウドネイティブ の実現に向けて
Java によるクラウドネイティブ の実現に向けてJava によるクラウドネイティブ の実現に向けて
Java によるクラウドネイティブ の実現に向けてShigeru Tatsuta
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話Koichiro Matsuoka
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろうKota Mizushima
 
「GraphDB徹底入門」〜構造や仕組み理解から使いどころ・種々のGraphDBの比較まで幅広く〜
「GraphDB徹底入門」〜構造や仕組み理解から使いどころ・種々のGraphDBの比較まで幅広く〜「GraphDB徹底入門」〜構造や仕組み理解から使いどころ・種々のGraphDBの比較まで幅広く〜
「GraphDB徹底入門」〜構造や仕組み理解から使いどころ・種々のGraphDBの比較まで幅広く〜Takahiro Inoue
 
GraalVM を普通の Java VM として使う ~クラウドベンチマークなどでの比較~
GraalVM を普通の Java VM として使う ~クラウドベンチマークなどでの比較~GraalVM を普通の Java VM として使う ~クラウドベンチマークなどでの比較~
GraalVM を普通の Java VM として使う ~クラウドベンチマークなどでの比較~Shinji Takao
 
Java 17直前!オレ流OpenJDK「の」開発環境(Open Source Conference 2021 Online/Kyoto 発表資料)
Java 17直前!オレ流OpenJDK「の」開発環境(Open Source Conference 2021 Online/Kyoto 発表資料)Java 17直前!オレ流OpenJDK「の」開発環境(Open Source Conference 2021 Online/Kyoto 発表資料)
Java 17直前!オレ流OpenJDK「の」開発環境(Open Source Conference 2021 Online/Kyoto 発表資料)NTT DATA Technology & Innovation
 

La actualidad más candente (20)

Akkaとは。アクターモデル とは。
Akkaとは。アクターモデル とは。Akkaとは。アクターモデル とは。
Akkaとは。アクターモデル とは。
 
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
 
最適なOpenJDKディストリビューションの選び方 #codetokyo19B3 #ccc_l5
最適なOpenJDKディストリビューションの選び方 #codetokyo19B3 #ccc_l5最適なOpenJDKディストリビューションの選び方 #codetokyo19B3 #ccc_l5
最適なOpenJDKディストリビューションの選び方 #codetokyo19B3 #ccc_l5
 
jcmd をさわってみよう
jcmd をさわってみようjcmd をさわってみよう
jcmd をさわってみよう
 
Java 9で進化する診断ツール
Java 9で進化する診断ツールJava 9で進化する診断ツール
Java 9で進化する診断ツール
 
デキるプログラマだけが知っているコードレビュー7つの秘訣
デキるプログラマだけが知っているコードレビュー7つの秘訣デキるプログラマだけが知っているコードレビュー7つの秘訣
デキるプログラマだけが知っているコードレビュー7つの秘訣
 
O/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐO/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐ
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
 
Unified JVM Logging
Unified JVM LoggingUnified JVM Logging
Unified JVM Logging
 
java.lang.OutOfMemoryError #渋谷java
java.lang.OutOfMemoryError #渋谷javajava.lang.OutOfMemoryError #渋谷java
java.lang.OutOfMemoryError #渋谷java
 
ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方
 
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~
 
SQL大量発行処理をいかにして高速化するか
SQL大量発行処理をいかにして高速化するかSQL大量発行処理をいかにして高速化するか
SQL大量発行処理をいかにして高速化するか
 
Java によるクラウドネイティブ の実現に向けて
Java によるクラウドネイティブ の実現に向けてJava によるクラウドネイティブ の実現に向けて
Java によるクラウドネイティブ の実現に向けて
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろう
 
「GraphDB徹底入門」〜構造や仕組み理解から使いどころ・種々のGraphDBの比較まで幅広く〜
「GraphDB徹底入門」〜構造や仕組み理解から使いどころ・種々のGraphDBの比較まで幅広く〜「GraphDB徹底入門」〜構造や仕組み理解から使いどころ・種々のGraphDBの比較まで幅広く〜
「GraphDB徹底入門」〜構造や仕組み理解から使いどころ・種々のGraphDBの比較まで幅広く〜
 
GraalVM を普通の Java VM として使う ~クラウドベンチマークなどでの比較~
GraalVM を普通の Java VM として使う ~クラウドベンチマークなどでの比較~GraalVM を普通の Java VM として使う ~クラウドベンチマークなどでの比較~
GraalVM を普通の Java VM として使う ~クラウドベンチマークなどでの比較~
 
Java 17直前!オレ流OpenJDK「の」開発環境(Open Source Conference 2021 Online/Kyoto 発表資料)
Java 17直前!オレ流OpenJDK「の」開発環境(Open Source Conference 2021 Online/Kyoto 発表資料)Java 17直前!オレ流OpenJDK「の」開発環境(Open Source Conference 2021 Online/Kyoto 発表資料)
Java 17直前!オレ流OpenJDK「の」開発環境(Open Source Conference 2021 Online/Kyoto 発表資料)
 

Destacado

だれも教えてくれないJavaの世界。 あと、ぼくが会社員になったわけ。
だれも教えてくれないJavaの世界。 あと、ぼくが会社員になったわけ。だれも教えてくれないJavaの世界。 あと、ぼくが会社員になったわけ。
だれも教えてくれないJavaの世界。 あと、ぼくが会社員になったわけ。なおき きしだ
 
Prepare for Java 9 #jjug
Prepare for Java 9 #jjugPrepare for Java 9 #jjug
Prepare for Java 9 #jjugYuji Kubota
 
Javaの登場と発展
Javaの登場と発展Javaの登場と発展
Javaの登場と発展Tamiya Onodera
 
JJUG CCC 2014 Spring IBM SDK for Java 8の全貌 #jjug_ccc #ccc_r57
JJUG CCC 2014 Spring IBM SDK for Java 8の全貌 #jjug_ccc #ccc_r57JJUG CCC 2014 Spring IBM SDK for Java 8の全貌 #jjug_ccc #ccc_r57
JJUG CCC 2014 Spring IBM SDK for Java 8の全貌 #jjug_ccc #ccc_r57Takakiyo Tanaka
 
タイムマシン採用:明日のエンタープライズJavaの世界を予想する -Java EE7/クラウド/Docker/etc.-
タイムマシン採用:明日のエンタープライズJavaの世界を予想する -Java EE7/クラウド/Docker/etc.-タイムマシン採用:明日のエンタープライズJavaの世界を予想する -Java EE7/クラウド/Docker/etc.-
タイムマシン採用:明日のエンタープライズJavaの世界を予想する -Java EE7/クラウド/Docker/etc.-Takakiyo Tanaka
 
Java開発の強力な相棒として今すぐ使えるGroovy
Java開発の強力な相棒として今すぐ使えるGroovyJava開発の強力な相棒として今すぐ使えるGroovy
Java開発の強力な相棒として今すぐ使えるGroovyYasuharu Nakano
 
2015/11/15 Javaでwebアプリケーション入門
2015/11/15 Javaでwebアプリケーション入門2015/11/15 Javaでwebアプリケーション入門
2015/11/15 Javaでwebアプリケーション入門Asami Abe
 
ほんとうに便利だった業務で使えるJava SE8新機能(JJUG CCC 2015 Spring)
ほんとうに便利だった業務で使えるJava SE8新機能(JJUG CCC 2015 Spring)ほんとうに便利だった業務で使えるJava SE8新機能(JJUG CCC 2015 Spring)
ほんとうに便利だった業務で使えるJava SE8新機能(JJUG CCC 2015 Spring)Yuuki Fukuda
 
Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~
Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~
Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~Masahito Zembutsu
 
Javaを勉強する上で知っておく
Javaを勉強する上で知っておくJavaを勉強する上で知っておく
Javaを勉強する上で知っておくYamazakiNobutoshi
 
Java の抽象クラス・インタフェース・無名クラスを理解しよう
Java の抽象クラス・インタフェース・無名クラスを理解しようJava の抽象クラス・インタフェース・無名クラスを理解しよう
Java の抽象クラス・インタフェース・無名クラスを理解しよう宗平 建矢
 
Overview mobile application advertising systems 16.08.2013
Overview mobile application advertising systems 16.08.2013Overview mobile application advertising systems 16.08.2013
Overview mobile application advertising systems 16.08.2013Quy Bui
 
Javaの資格試験(OCJ-P)を取って何を学んだか
Javaの資格試験(OCJ-P)を取って何を学んだかJavaの資格試験(OCJ-P)を取って何を学んだか
Javaの資格試験(OCJ-P)を取って何を学んだかHiroki Uchida
 
Seccamp 2016 チューター成果報告
Seccamp 2016 チューター成果報告Seccamp 2016 チューター成果報告
Seccamp 2016 チューター成果報告slankdev
 
NoSQL for great good [hanoi.rb talk]
NoSQL for great good [hanoi.rb talk]NoSQL for great good [hanoi.rb talk]
NoSQL for great good [hanoi.rb talk]Huy Do
 
Java初心者がJava8のラムダ式をやってみた
Java初心者がJava8のラムダ式をやってみたJava初心者がJava8のラムダ式をやってみた
Java初心者がJava8のラムダ式をやってみたAya Ebata
 
Processingでジャバジャバ稼ぐ
Processingでジャバジャバ稼ぐProcessingでジャバジャバ稼ぐ
Processingでジャバジャバ稼ぐreona396
 
スタートアップの開発体制、流れ POPULAR PATTERN
スタートアップの開発体制、流れ POPULAR PATTERNスタートアップの開発体制、流れ POPULAR PATTERN
スタートアップの開発体制、流れ POPULAR PATTERNKoichiro Sumi
 

Destacado (20)

だれも教えてくれないJavaの世界。 あと、ぼくが会社員になったわけ。
だれも教えてくれないJavaの世界。 あと、ぼくが会社員になったわけ。だれも教えてくれないJavaの世界。 あと、ぼくが会社員になったわけ。
だれも教えてくれないJavaの世界。 あと、ぼくが会社員になったわけ。
 
Prepare for Java 9 #jjug
Prepare for Java 9 #jjugPrepare for Java 9 #jjug
Prepare for Java 9 #jjug
 
Javaの登場と発展
Javaの登場と発展Javaの登場と発展
Javaの登場と発展
 
JJUG CCC 2014 Spring IBM SDK for Java 8の全貌 #jjug_ccc #ccc_r57
JJUG CCC 2014 Spring IBM SDK for Java 8の全貌 #jjug_ccc #ccc_r57JJUG CCC 2014 Spring IBM SDK for Java 8の全貌 #jjug_ccc #ccc_r57
JJUG CCC 2014 Spring IBM SDK for Java 8の全貌 #jjug_ccc #ccc_r57
 
タイムマシン採用:明日のエンタープライズJavaの世界を予想する -Java EE7/クラウド/Docker/etc.-
タイムマシン採用:明日のエンタープライズJavaの世界を予想する -Java EE7/クラウド/Docker/etc.-タイムマシン採用:明日のエンタープライズJavaの世界を予想する -Java EE7/クラウド/Docker/etc.-
タイムマシン採用:明日のエンタープライズJavaの世界を予想する -Java EE7/クラウド/Docker/etc.-
 
Java開発の強力な相棒として今すぐ使えるGroovy
Java開発の強力な相棒として今すぐ使えるGroovyJava開発の強力な相棒として今すぐ使えるGroovy
Java開発の強力な相棒として今すぐ使えるGroovy
 
How to Design Indexes, Really
How to Design Indexes, ReallyHow to Design Indexes, Really
How to Design Indexes, Really
 
2015/11/15 Javaでwebアプリケーション入門
2015/11/15 Javaでwebアプリケーション入門2015/11/15 Javaでwebアプリケーション入門
2015/11/15 Javaでwebアプリケーション入門
 
ほんとうに便利だった業務で使えるJava SE8新機能(JJUG CCC 2015 Spring)
ほんとうに便利だった業務で使えるJava SE8新機能(JJUG CCC 2015 Spring)ほんとうに便利だった業務で使えるJava SE8新機能(JJUG CCC 2015 Spring)
ほんとうに便利だった業務で使えるJava SE8新機能(JJUG CCC 2015 Spring)
 
Hello Java
Hello JavaHello Java
Hello Java
 
Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~
Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~
Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~
 
Javaを勉強する上で知っておく
Javaを勉強する上で知っておくJavaを勉強する上で知っておく
Javaを勉強する上で知っておく
 
Java の抽象クラス・インタフェース・無名クラスを理解しよう
Java の抽象クラス・インタフェース・無名クラスを理解しようJava の抽象クラス・インタフェース・無名クラスを理解しよう
Java の抽象クラス・インタフェース・無名クラスを理解しよう
 
Overview mobile application advertising systems 16.08.2013
Overview mobile application advertising systems 16.08.2013Overview mobile application advertising systems 16.08.2013
Overview mobile application advertising systems 16.08.2013
 
Javaの資格試験(OCJ-P)を取って何を学んだか
Javaの資格試験(OCJ-P)を取って何を学んだかJavaの資格試験(OCJ-P)を取って何を学んだか
Javaの資格試験(OCJ-P)を取って何を学んだか
 
Seccamp 2016 チューター成果報告
Seccamp 2016 チューター成果報告Seccamp 2016 チューター成果報告
Seccamp 2016 チューター成果報告
 
NoSQL for great good [hanoi.rb talk]
NoSQL for great good [hanoi.rb talk]NoSQL for great good [hanoi.rb talk]
NoSQL for great good [hanoi.rb talk]
 
Java初心者がJava8のラムダ式をやってみた
Java初心者がJava8のラムダ式をやってみたJava初心者がJava8のラムダ式をやってみた
Java初心者がJava8のラムダ式をやってみた
 
Processingでジャバジャバ稼ぐ
Processingでジャバジャバ稼ぐProcessingでジャバジャバ稼ぐ
Processingでジャバジャバ稼ぐ
 
スタートアップの開発体制、流れ POPULAR PATTERN
スタートアップの開発体制、流れ POPULAR PATTERNスタートアップの開発体制、流れ POPULAR PATTERN
スタートアップの開発体制、流れ POPULAR PATTERN
 

Similar a Java仮想マシンの実装技術

Head toward Java 16 (Night Seminar Edition)
Head toward Java 16 (Night Seminar Edition)Head toward Java 16 (Night Seminar Edition)
Head toward Java 16 (Night Seminar Edition)Yuji Kubota
 
Application Architecture for Enterprise Win Store Apps with DDD Pattern
Application Architecture for Enterprise Win Store Apps with DDD PatternApplication Architecture for Enterprise Win Store Apps with DDD Pattern
Application Architecture for Enterprise Win Store Apps with DDD PatternAtsushi Kambara
 
Java/Androidセキュアコーディング
Java/AndroidセキュアコーディングJava/Androidセキュアコーディング
Java/AndroidセキュアコーディングMasaki Kubo
 
SDLoader SeasarCon 2009 Whire
SDLoader SeasarCon 2009 WhireSDLoader SeasarCon 2009 Whire
SDLoader SeasarCon 2009 WhireAkio Katayama
 
JavaScript.Next
JavaScript.NextJavaScript.Next
JavaScript.Nextdynamis
 
R5 3 type annotation
R5 3 type annotationR5 3 type annotation
R5 3 type annotationEIICHI KIMURA
 
Seasarプロジェクト徹底攻略
Seasarプロジェクト徹底攻略Seasarプロジェクト徹底攻略
Seasarプロジェクト徹底攻略takezoe
 
JavaFX & GlassFish 勉強会 Oh! JavaFX 2.0!
JavaFX & GlassFish 勉強会 Oh! JavaFX 2.0!JavaFX & GlassFish 勉強会 Oh! JavaFX 2.0!
JavaFX & GlassFish 勉強会 Oh! JavaFX 2.0!Yuichi Sakuraba
 
Groovyで楽にSQLを実行してみよう
Groovyで楽にSQLを実行してみようGroovyで楽にSQLを実行してみよう
Groovyで楽にSQLを実行してみようAkira Shimosako
 
Beginning Java EE 6 勉強会(3) #bje_study
Beginning Java EE 6 勉強会(3) #bje_studyBeginning Java EE 6 勉強会(3) #bje_study
Beginning Java EE 6 勉強会(3) #bje_studyinatus
 
[豆ナイト]Java small object programming
[豆ナイト]Java small object programming[豆ナイト]Java small object programming
[豆ナイト]Java small object programmingYuichi Hasegawa
 
HeapStats @ Seasar Conference 2015 LT
HeapStats @ Seasar Conference 2015 LTHeapStats @ Seasar Conference 2015 LT
HeapStats @ Seasar Conference 2015 LTYuji Kubota
 
JavaScript.Next Returns
JavaScript.Next ReturnsJavaScript.Next Returns
JavaScript.Next Returnsdynamis
 
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~Akira Inoue
 
Agileツール適合化分科会(構成管理・ビルドツール)
Agileツール適合化分科会(構成管理・ビルドツール)Agileツール適合化分科会(構成管理・ビルドツール)
Agileツール適合化分科会(構成管理・ビルドツール)masanori kataoka
 
SeleniumE2Eテストフレームワークを使用したテスト自動化事例 #Seleniumjp
SeleniumE2Eテストフレームワークを使用したテスト自動化事例 #SeleniumjpSeleniumE2Eテストフレームワークを使用したテスト自動化事例 #Seleniumjp
SeleniumE2Eテストフレームワークを使用したテスト自動化事例 #SeleniumjpYahoo!デベロッパーネットワーク
 
JJUG CCC 2012 Real World Groovy/Grails
JJUG CCC 2012 Real World Groovy/GrailsJJUG CCC 2012 Real World Groovy/Grails
JJUG CCC 2012 Real World Groovy/GrailsUehara Junji
 

Similar a Java仮想マシンの実装技術 (20)

Head toward Java 16 (Night Seminar Edition)
Head toward Java 16 (Night Seminar Edition)Head toward Java 16 (Night Seminar Edition)
Head toward Java 16 (Night Seminar Edition)
 
Application Architecture for Enterprise Win Store Apps with DDD Pattern
Application Architecture for Enterprise Win Store Apps with DDD PatternApplication Architecture for Enterprise Win Store Apps with DDD Pattern
Application Architecture for Enterprise Win Store Apps with DDD Pattern
 
Java/Androidセキュアコーディング
Java/AndroidセキュアコーディングJava/Androidセキュアコーディング
Java/Androidセキュアコーディング
 
Cve 2013-0422
Cve 2013-0422Cve 2013-0422
Cve 2013-0422
 
SDLoader SeasarCon 2009 Whire
SDLoader SeasarCon 2009 WhireSDLoader SeasarCon 2009 Whire
SDLoader SeasarCon 2009 Whire
 
JavaScript.Next
JavaScript.NextJavaScript.Next
JavaScript.Next
 
R5 3 type annotation
R5 3 type annotationR5 3 type annotation
R5 3 type annotation
 
Seasarプロジェクト徹底攻略
Seasarプロジェクト徹底攻略Seasarプロジェクト徹底攻略
Seasarプロジェクト徹底攻略
 
JavaFX & GlassFish 勉強会 Oh! JavaFX 2.0!
JavaFX & GlassFish 勉強会 Oh! JavaFX 2.0!JavaFX & GlassFish 勉強会 Oh! JavaFX 2.0!
JavaFX & GlassFish 勉強会 Oh! JavaFX 2.0!
 
Groovyで楽にSQLを実行してみよう
Groovyで楽にSQLを実行してみようGroovyで楽にSQLを実行してみよう
Groovyで楽にSQLを実行してみよう
 
Rx java x retrofit
Rx java x retrofitRx java x retrofit
Rx java x retrofit
 
Beginning Java EE 6 勉強会(3) #bje_study
Beginning Java EE 6 勉強会(3) #bje_studyBeginning Java EE 6 勉強会(3) #bje_study
Beginning Java EE 6 勉強会(3) #bje_study
 
ScalaMatsuri 2016
ScalaMatsuri 2016ScalaMatsuri 2016
ScalaMatsuri 2016
 
[豆ナイト]Java small object programming
[豆ナイト]Java small object programming[豆ナイト]Java small object programming
[豆ナイト]Java small object programming
 
HeapStats @ Seasar Conference 2015 LT
HeapStats @ Seasar Conference 2015 LTHeapStats @ Seasar Conference 2015 LT
HeapStats @ Seasar Conference 2015 LT
 
JavaScript.Next Returns
JavaScript.Next ReturnsJavaScript.Next Returns
JavaScript.Next Returns
 
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
 
Agileツール適合化分科会(構成管理・ビルドツール)
Agileツール適合化分科会(構成管理・ビルドツール)Agileツール適合化分科会(構成管理・ビルドツール)
Agileツール適合化分科会(構成管理・ビルドツール)
 
SeleniumE2Eテストフレームワークを使用したテスト自動化事例 #Seleniumjp
SeleniumE2Eテストフレームワークを使用したテスト自動化事例 #SeleniumjpSeleniumE2Eテストフレームワークを使用したテスト自動化事例 #Seleniumjp
SeleniumE2Eテストフレームワークを使用したテスト自動化事例 #Seleniumjp
 
JJUG CCC 2012 Real World Groovy/Grails
JJUG CCC 2012 Real World Groovy/GrailsJJUG CCC 2012 Real World Groovy/Grails
JJUG CCC 2012 Real World Groovy/Grails
 

Java仮想マシンの実装技術

  • 1. 2016年年9⽉月6⽇日 河内⾕谷清久仁 http://ibm.biz/kawatiya ⽇日本アイ・ビー・エム(株) 東京基礎研究所 (資料料作成協⼒力力:緒⽅方⼀一則,⼩小笠笠原武史,仲池卓也) PPLサマースクール2016「商⽤用Java処理理系の研究開発」 Java仮想マシンの実装技術 2016/09/061 Java仮想マシンの実装技術 / 河内⾕谷清久仁 JavaTMおよびすべてのJava関連の 商標およびロゴはOracleやその関連 会社の米国およびその他の国にお ける商標または登録商標です.
  • 2. ©  2016  IBM  Corporation 概要:⽇日本アイ・ビー・エム(株)東京基礎研究所はJava⾔言語の黎黎明期からその処理理系に関する研究開発を リードし,IBM開発部⾨門と協業して業務アプリケーションの基盤として使われるJava処理理系を世に送り出して きた.特に,Just-­‐In-­‐TimeコンパイラとJava仮想マシンの主要構成要素については各種の先進的技術を考案し, 世界トップクラスの性能を達成するとともに,多数の学会発表も⾏行行ってきている.本セミナーでは,この商 ⽤用Java処理理系の研究開発に関する経験をもとに,以下の内容について述べる. 1  Javaの登場と発展(30分,講師:⼩小野寺⺠民也) 1995年年のJavaの登場とその後の受容の過程を概観し,Java登場時にどのような性能上の課題があったかを述 べ,続く2つのセッションへの導⼊入とする.また,性能向上の研究開発における標準ベンチマークの重要さ についても⾔言及する. 2  Java仮想マシンの実装技術(2時間,講師:河内⾕谷清久仁) Java⾔言語処理理系の実装について詳説する.まずJava仮想マシンの概要について述べ,その主要な構成要素と して,クラス管理理とインタープリタ,ヒープ管理理とガベージコレクション,スレッド管理理と同期機構,JIT コンパイラとの連携,などについて説明する.性能改善のために⾏行行った各種⼿手法についても触れる. 3  Java  Just-­‐In-­‐Timeコンパイラの実装技術(2時間,講師:⽯石崎⼀一明) Javaの動的コンパイラの実装について詳説する.まず構成の概要について述べ,主な最適化,動的コンパ イラ特有の最適化,Java⾔言語特有の最適化,について説明する.また,Java⾔言語からSIMDやGPUなどのハー ドウェア機構を使う試みについても述べる.商⽤用コンパイラの実装に関する経験談についても触れる. 4  まとめと展望(1時間,講師:⼩小野寺⺠民也) まとめとして,プログラミング⾔言語の実装技術の歴史を概観し,Javaの誕⽣生と発展に果たした役割につい て考えてみたい(内容は予告なく変更更することがありますw). 2016/09/062 商⽤用Java処理理系の研究開発 Java仮想マシンの実装技術 / 河内⾕谷清久仁
  • 3. ©  2016  IBM  Corporation2016/09/063 講師紹介 ⼩小野寺 ⺠民也(おのでら たみや) http://ibm.biz/onodera ⽇日本アイ・ビー・エム(株)技術理理事,東京基礎研究所 サービス型コンピューティング 部⻑⾧長.1988年年東京 ⼤大学⼤大学院理理学系研究科情報科学専⾨門課程博⼠士課程修了了.同年年⽇日本アイ・ビー・エム(株)⼊入社.以来, 同社東京基礎研究所にて,プログラミング⾔言語およびミドルウェアおよびシステムソフトウェアの研究開 発に従事. 情報処理理学会第41回(平成2年年後期)全国⼤大会学術奨励賞,同平成7年年度度⼭山下記念念研究賞,同平 成16年年度度論論⽂文賞,同平成16年年度度業績賞,各受賞.理理学博⼠士.⽇日本ソフトウェア科学会会員(元・理理事), 情報処理理学会シニア会員,ACM  Distinguished  Scientist. 河内⾕谷 清久仁(かわちや きよくに) http://ibm.biz/kawatiya ⽇日本アイ・ビー・エム(株)シニア・テクニカル・スタッフ・メンバー,東京基礎研究所 ディープ・コン ピューティング&アナリティクス 部⻑⾧長.1987年年東京⼤大学⼤大学院理理学系研究科情報科学専攻修⼠士課程修了了. 同年年⽇日本アイ・ビー・エム(株)⼊入社.以来,同社東京基礎研究所にてOSやプログラミング⾔言語処理理系な どの研究に従事.最近は,Javaの性能問題分析などにも携わる.博⼠士(政策・メディア).1994年年情報処 理理学会⼤大会奨励賞,2005年年同・論論⽂文賞,2008年年⽇日本ソフトウェア科学会⾼高橋奨励賞,各受賞.⽇日本ソフト ウェア科学会編集副委員⻑⾧長(元・理理事),情報処理理学会シニア会員,ACM  Distinguished  Engineer. ⽯石崎 ⼀一明(いしざき かずあき) http://ibm.biz/ishizaki ⽇日本アイ・ビー・エム(株)東京基礎研究所 リサーチ・スタッフ・メンバー.1992年年早稲⽥田⼤大学理理⼯工学研 究科修⼠士課程修了了.同年年⽇日本アイ・ビー・エム(株)⼊入社.以来,同社東京基礎研究所にて,Fortran⾔言語 の並列列化コンパイラ,Java⾔言語の動的コンパイラ,Python⾔言語の動的コンパイラ,などのプログラミング ⾔言語処理理系の研究に従事.最近は,JavaやApache  Sparkからの,GPUその他アクセラレータ活⽤用⽅方法に興味 を持つ.情報処理理学会平成16年年度度業績賞受賞.博⼠士(情報科学).⽇日本ソフトウェア科学会理理事,情報処 理理学会会員,ACM  Senior  Member. Java仮想マシンの実装技術 / 河内⾕谷清久仁
  • 4. ©  2016  IBM  Corporation 概要:Java⾔言語処理理系の実装について詳説する.まずJava仮想マシンの概要について述べ,その 主要な構成要素として,クラス管理理とインタープリタ,ヒープ管理理とガベージコレクション, スレッド管理理と同期機構,JITコンパイラとの連携,などについて説明する.性能改善のため に⾏行行った各種⼿手法についても触れる. § カバーする内容 – クラス管理理 – メソッド呼び出しとJIT連携 – バイトコードとインタープリタ – オブジェクト管理理とGC – スレッド管理理と同期機構 – 例例外処理理 – (JITコンパイラ超⼊入⾨門) 無記名アンケートへのご協⼒力力をお願いします (⼀一部だけの回答も可能です) 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁4 Java仮想マシンの実装技術 クラス管理 オブジェクト 管理 インタープリタ JIT コンパイラ JITコンパイラ 生成コード 実行時 プロファイラ クラスデータ (Java  バイト コード) Javaヒープ (Java  オブ ジェクト) Javaスタック (ローカル変数, オペランドスタック) Java仮想マシン(Java  VM) Java同期 ランタイム Java例外処理 ランタイム JVM ランタイム
  • 5. ©  2016  IBM  Corporation § この講演では,⻘青で囲ったもの について説明する – JITコンパイラとプロファイラ については,次の講演で詳説 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁5 Java  VMの主要コンポーネントとデータ構造 クラス管理 オブジェクト 管理 インタープリタ JIT コンパイラ JITコンパイラ 生成コード 実行時 プロファイラ クラスデータ (Java  バイト コード) Javaヒープ (Java  オブ ジェクト) Javaスタック (ローカル変数, オペランドスタック) OS  /  標準ライブラリ Java仮想マシン(Java  VM) Java同期 ランタイム Java例外処理 ランタイム JVM ランタイム Java ソースコード (.javaファイル) javac クラスファイル (.classファイル, .jarファイル) プログラム作成時に 行う処理
  • 6. ©  2016  IBM  Corporation Javaクラスファイルの作成と実⾏行行 6 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁 Java ソースコード (.javaファイル) javac クラスファイル (.classファイル, .jarファイル) プログラム作成時に 行う処理 class  Hello  { public  static  void  main(String[  ]  args)  { System.out.println("Hello  Java");; } } Hello.java $  javac Hello.java $  ls Hello.class Hello.java $ java Hello Hello Java $  
  • 7. ©  2016  IBM  Corporation § クラスごとに作られる,構造を持ったバイナリファイル 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁7 クラスファイル 0xCAFEBABE major_versionは,「javac -­target」のJRE バージョンによって変わる(45~52) 定数表(リテラル,識別子など) このクラスで定義しているメソッドの 情報(継承したものは含まない) クラスのアクセス権や 親クラスなどのメタ情報 Implements  している インターフェースの一覧 クラス内のフィールドの一覧 バイトコード,デバッグ情報など. Attributeセクションは何個あってもよい “The  Java  Virtual  Machine Specification”  より
  • 9. ©  2016  IBM  Corporation § クラスファイルを読み込み, そのライフサイクルを管理理 するコンポーネント § サブコンポーネント – クラスローダ § クラスファイルを検索索 し,メモリ(クラス データ領領域)に展開 – ベリファイア § ロードしたクラスファ イルにエラーがないこ とを確認 – Constant  pool(定数表) § リテラルやシンボル情報を保持 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁9 クラス管理理 クラス管理 オブジェクト 管理 インタープリタ JIT コンパイラ JITコンパイラ 生成コード 実行時 プロファイラ クラスデータ (Java  バイト コード) Javaヒープ (Java  オブ ジェクト) Javaスタック (ローカル変数, オペランドスタック) Java仮想マシン(Java  VM) Java同期 ランタイム Java例外処理 ランタイム JVM ランタイム Java ソースコード (.javaファイル) javac クラスファイル (.classファイル, .jarファイル) プログラム作成時に 行う処理
  • 10. ©  2016  IBM  Corporation § メモリ上に読み込んだクラスファイルをJava  VMに渡して,クラスとして登録する – クラスパスに従ってクラスファイルを探し,クラスデータ領領域に読み込む – クラスファイルの構造をメモリ上に 直接⽣生成してもよい § クラスローダ⾃自体もJavaオブジェクト – java.lang.ClassLoaderクラス(のサブ クラス)のインスタンス – Java  VMがデフォルトで⽣生成するもの が3個ある – ユーザが⽣生成することも可能 § クラスアンロード – 参照されなくなったクラスは, クラスローダ単位でアンロード可能 – 動的置き換え可能なモジュールの 実装に利利⽤用されている § EclipseなどのプラグインやEJB 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁10 クラスローダ クラスデータ領域 ユーザプログラムの クラス群 System class  loader 標準クラス群 Bootstrap   class    loader jre/lib/ext にある JARファイルから ロードされたクラス 群 Extension   class  loader Helloクラス constant_pool Field定義 Method定義 バイトコード, デバッグ情報など java.lang.Object java.lang.String Hello.class読み込み後のクラスデータ構造
  • 11. ©  2016  IBM  Corporation クラスデータ領域 ロードされたクラス(イメージ) 11 Java仮想マシンの実装技術2016/09/06 クラスS constant_pool フィールド定義 S.m1の バイトコード S.m2の バイトコード 管理情報 S.m1の メソッド情報 vtable S.m2の メソッド情報 クラスA constant_pool フィールド定義 管理情報 vtable クラスB constant_pool フィールド定義 管理情報 vtable A.m2の メソッド情報 A.m3の メソッド情報 B.m3の メソッド情報 B.m3の バイトコード itable A.m2の バイトコード A.m3の バイトコード itable itable class  S  { int val =  1234;; void  m1()  {  …  } void  m2()  {  …  } } interface  I  {  void  m3();;  } class  A  extends  S implements  I  { void  m2()  {  …  } void  m3()  {  …  } } class  B  implements  I,J  { void  m3()  {  …  } }
  • 12. ©  2016  IBM  Corporation クラスデータ領域 § オブジェクトのクラスに よって,呼ばれるメソッ ドが変わる § JITされたコードがあれば, そちらが呼ばれる 2016/09/06 Java仮想マシンの実装技術12 メソッド管理理:仮想メソッドの呼び出し class  S  { int val =  1234;; void  m1()  {  …  } void  m2()  {  …  } } interface  I  {  void  m3();;  } class  A  extends  S implements  I  { void  m2()  {  …  } void  m3()  {  …  } } class  B  implements  I,J  { void  m3()  {  …  } } クラスS constant_pool フィールド定義 S.m1の バイトコード S.m2の バイトコード 管理情報 S.m1の メソッド情報 vtable [1]  (m1) [2]  (m2) クラスA constant_pool フィールド定義 A.m2の バイトコード 管理情報 vtable [1]  (m1) [2]  (m2) [3]  (m3) S.m2の メソッド情報 A.m2の メソッド情報 A.m3の メソッド情報 S  p  =  new  S();; p.m2();;  //  à S.m2 S  q  =  new  A();; q.m2();;  //  à A.m2 p q A.m2の JITされた コード interface  I m3àvtable[3] A.m3の バイトコード
  • 13. ©  2016  IBM  Corporation クラスデータ領域 § インタフェース関数の呼 び出しは,同じ名前でも 同じvtableオフセットに ならない § クラスデータのitableを スキャンして対応するイ ンタフェースを探し,メ ソッドに対応するvtable エントリを得る 2016/09/06 Java仮想マシンの実装技術13 メソッド管理理:インタフェースメソッドの呼び出し class  S  { int val =  1234;; void  m1()  {  …  } void  m2()  {  …  } } interface  I  {  void  m3();;  } class  A  extends  S implements  I  { void  m2()  {  …  } void  m3()  {  …  } } class  B  implements  I,J  { void  m3()  {  …  } } クラスA constant_pool フィールド定義 管理情報 vtable [1]  (m1) [2]  (m2) [3]  (m3) クラスB constant_pool フィールド定義 管理情報 vtable [1]  (m3) A.m2の メソッド情報 A.m3の メソッド情報 B.m3の メソッド情報 B.m3の バイトコード I  p  =  new  A();; p.m3();;  //  à A.m3 I  q  =  new  B();; q.m3();;  //  à B.m3 interface  “I” m3àvtable[3] A.m2の バイトコード A.m3の バイトコード interface  “I” m3àvtable[1] interface  “J” … …
  • 14. ©  2016  IBM  Corporation2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁14 Javaバイトコード class  Hello  { static  int val =  1234567;; private  void  Hello() { super();; } public  static  void  main(…) { System.out. println("Hello  Java");; System.out. println(val);; } } Hello.java class  Hello  extends  java.lang.Object { static  {} 0:      ldc #7;;    //int 1234567 2:      putstatic #5;;    //Field  val 5:      return private  void  <init>();; 0:    aload_0 1:    invokespecial #1 4:    return public  static  void  main(java.lang.String[]);; 0:      getstatic #2;;    //Field      java.lang.System.out 3:      ldc #3;;    //String    "Hello  Java" 5:      invokevirtual #4;;    //Method  println(String) 8:      getstatic #2;;    //Field      java.lang.System.out 11:      getstatic #5;;    //Field      val 14:      invokevirtual #6;;    //Method  println(int) 17:      return } Hello.classのバイトコード javac § Javacが暗黙に⽣生成するメソッドがある § 多くの命令令が「定数表」を参照
  • 15. ©  2016  IBM  Corporation2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁15 定数表(Constant  Pool) class  Hello  extends  java.lang.Object { static  {} 0:      ldc #7;;    //int 1234567 2:      putstatic #5;;    //Field  val 5:      return private  void  <init>();; 0:    aload_0 1:    invokespecial #1 4:    return public  static  void  main(java.lang.String[]);; 0:      getstatic #2;;    //Field      java.lang.System.out 3:      ldc #3;;    //String    "Hello  Java" 5:      invokevirtual #4;;    //Method  println(String) 8:      getstatic #2;;    //Field      java.lang.System.out 11:      getstatic #5;;    //Field      val 14:      invokevirtual #6;;    //Method  println(int) 17:      return } Hello.classのバイトコード String  "Hello  Java" 1234567 System.out java.lang.System "out" PrintStrem.println(String) java.io.PrintStream "println" "(Ljava/lang/String;;)V" Fieldref Methodref Name&Type UTF8 UTF8 UTF8 String Type val Int Object.<init>() PrintStrem.println(int) Index 0 1 2 3 4 5 6 7 9 11 12 14 15 16 Class Methodref println(String) 8 Class Fieldref Methodref "Hello  Java"UTF8 "Ljava/io/PrintStream;;"UTF8 13 "Ljava/lang/System;;"UTF8 10 Constant_pool
  • 16. ©  2016  IBM  Corporation § Constant  poolは,クラスごとに作成されるデータ構造で,以下の内容を保持 – プログラム中のリテラル値 – フィールドやメソッドへの参照 § シンボル名(クラス名,メソッド名など) § Resolve後の状態 § Resolve – フィールドやメソッドへの参照を解決する処理理 § その参照への,初回のアクセス時に⾏行行われる § 参照先クラスがロードされていなければロードする § アクセス権のチェックが⾏行行われる – Resolve時に,参照情報のデータ形式を最適化することが多い § クラスロード直後は,参照対象は⽂文字列列形式で保持される § Resolve後は,参照対象へのポインタを保持するように書き換えられる – ⼀一旦Resolveされればその後は⾼高速に参照可能 § インタープリタでResolveしてしまい,JITedコードではResolve後の値を使うのがよい 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁16 シンボル参照の解決(Resolve) Stringオブジェクトへの参照 1234567 &System.out &PrintStrem.println(String) Fieldref Methodref String &val Int &Object.<init>() &PrintStrem.println(int) 0 1 2 3 4 5 6 7 Methodref Fieldref Methodref Resolve後のconstant pool
  • 18. ©  2016  IBM  Corporation § インタープリタとJust-­‐in-­‐Time(JIT)コンパイラ を組み合わせる処理理系が多い – インタープリタだけを使う処理理系や, JITコンパイラだけの処理理系(Jikes RVMなど) もある § Ahead-­‐of-­‐Time(AOT)コンパイラを使う処理理系 もある – Real-­‐time  Javaや,巨⼤大アプリの起動時間 短縮に有効 § 実⾏行行時プロファイラを⽤用いて,JITコンパイラ による最適化に有益な情報を収集することも ある 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁18 バイトコードの実⾏行行(インタープリタ) クラス管理 オブジェクト 管理 インタープリタ JIT コンパイラ JITコンパイラ 生成コード 実行時 プロファイラ クラスデータ (Java  バイト コード) Javaヒープ (Java  オブ ジェクト) Javaスタック (ローカル変数, オペランドスタック) Java仮想マシン(Java  VM) Java同期 ランタイム Java例外処理 ランタイム JVM ランタイム
  • 19. ©  2016  IBM  Corporation § スタック・アーキテクチャの命令令セット – 操作対象のスタックを「オペランド・スタック」と呼ぶ – 基本的に型付きの命令令(スタック要素も型付き) § 1〜~3バイトの可変⻑⾧長(⼀一部例例外あり) 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁19 Javaバイトコード 0x60 opcode   (0x60) 1  byte iadd 0xb4getfield   0x01 opcode (0xb4) 1  byte 0x23 0x1234 0x5678 0x68AC Field  valObj  ref SP SP SPSP バイトコード オペランドスタックの操作 operand (0x0123)
  • 20. ©  2016  IBM  Corporation § 実⾏行行中のメソッドの「フレーム」が保持される領領域 § フレームに格納されるデータ – カレントクラスなどのリンク情報 – メソッド呼び出しチェーン情報 – ローカル変数 § メソッド呼び出し時は,callerとcalleeのフレームの ⼀一部が重なる 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁20 Javaスタック SP ローカル 変数領域 SP ローカル 変数領域 0x1234 obj1 0x1234 ローカル 変数領域 obj1.foo(2) の呼び出し 2 Frame   data Frame   data Frame   data Callerの フレーム Callerの フレーム Calleeの フレーム Callee の引数 Callerの スタック Callerの スタック obj1 2
  • 21. ©  2016  IBM  Corporation § Mixed-­‐mode  Execution – インタープリタとJITコンパイラを併⽤用する実⾏行行⽅方式 – 実⾏行行頻度度の⾼高いところだけ,実⾏行行中にコンパイルしてネイティブコードに変換 – この講演では,インタープリタにフォーカス(JITについては次の講演で) § バイトコード・インタープリタの基本構造 – デコード・ループ § 1命令令読み込んで,対応するハンドラを呼び出し,ハンドラから戻ってきたら次の命 令令を読み込むループ – ハンドラ(群) § バイトコード命令令で定義された処理理を⾏行行うサブルーチン 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁21 バイトコードの実⾏行行 デコード・ ループ ハンドラ1 ハンドラ2 バイトコード
  • 22. ©  2016  IBM  Corporation § 基本構造をC⾔言語で実装するなら,ハンドラごとに関数を作る 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁22 バイトコード・インタープリタの基本的な実装例例 char  *pc  =  getBytecodeAddr(); int *sp =  getStackBottom(); void (*decodeTbl[])(char**,int**)={ &op00_handler,   /*0x00*/ ... &op04_handler,   /*0x04*/ ... &op60_handler,   /*0x60*/ ...  }; while(TRUE)   { (*decodeTbl[*pc++])(&pc,&sp); } デコード・ループ 0x1234 0x5678 0x68ACiadd SP SP op00_handler(char   **pc,int **sp){ /*  0x00:  nop */ return;  } op60_handler(char   **pc,int **sp){   /*  0x60:  iadd */ (*sp)[1]   +=  (*sp)[0];   ++*sp; return;  } op04_handler(char   **pc,int **sp){   /*  0x04:  iconst_1   */ (-­‐-­‐*sp)[0]  =  1; return;  }
  • 23. ©  2016  IBM  Corporation インタープリタの⾼高速化 23 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁
  • 24. ©  2016  IBM  Corporation § プログラム起動時は,JITコンパイルしない⽅方が速い [Suganuma’01] – その場合,インタープリタの⾼高速化により起動時間を短縮できる § また,JITコンパイルするメソッドを減らせば,JITではなくプログラム実⾏行行に時間を使える 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁24 インタープリタ⾼高速化の必要性 [Suganuma ‘01]  T.  Suganuma et  al.    A  Dynamic  Optimization Framework  for  a  Java  Just-­In-­ Time  Compiler.    OOPSLA  ’01 遅い←→速い スタートアップの性能⽐比較 全部full-­‐JITす るととても遅い JITしない⽅方が アプリ起動は速い Java:  IBM  JDK  1.3.0 HW:  Pentium  III  600  MHz,  512MB  Memory OS:  Windows  2000  SP1
  • 25. ©  2016  IBM  Corporation § 頻繁に分岐命令令を実⾏行行するので,コードが分断される – デコード・ループもハンドラも,短く,並列列度度の低いコード § ループであっても,命令令読み込みとデコードを繰り返す 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁25 バイトコード・インタープリタのオーバーヘッド TOS: Top of Stack i2s ハンドラ ineg ハンドラ ifgt ハンドラ iload_3 ハンドラ 例:「while(  (short)(-­x)  >  0  );;」のデコード操作 xをpush 符号反転 short型に変換 TOS>0なら ジャンプ デコード・ ループ ff faバイトコード 9d93741d
  • 26. ©  2016  IBM  Corporation § デコード・ループを全てのハンドラにコピーして間接分岐の実⾏行行回数を減らす – 各ハンドラの最後で次のバイトコードをデコードし,そのハンドラへ直接ジャンプする § アドレス計算の⾼高速化⼿手法もいろいろある – ハンドラを固定サイズにしてバイトコード順に並べれば,算術演算でアドレス取得も可能 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁26 解決法の例例:Threaded  Code  [Bell’73,  Ritter’80] iload_3 ハンドラ ineg ハンドラ バイト コード &iload_3 &i2s &ineg ハンドラ アドレス 表 デコード& ジャンプ デコード& ジャンプ デコード&ジャンプ 1d 74 93
  • 27. ©  2016  IBM  Corporation § スタック・アーキテクチャの仮想マシンでは, スタック・トップ(Top  of  Stack=TOS)近辺の値を頻繁にアクセスする § 同じメモリを何度度もアクセスする場合がある 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁27 スタック・アーキテクチャ仮想マシンのボトルネック SP 0xFFFF SP 0x0001 i2s ハンドラ ineg ハンドラ ifgt ハンドラ iload_3 ハンドラ 例:「while(  (short)(-­x)  >  0  );;」のスタック操作 xをpush 符号反転 short型に変換 TOS>0なら ジャンプ 0x0001 SP SP SP
  • 28. ©  2016  IBM  Corporation § スタック・トップ(TOS)近辺の値をレジスタにキャッシュする – Write-­‐through  cacheかwrite-­‐backにするかは,実装依存 § 問題点 – 常にTOSをキャッシュすると,無駄な読み込みが発⽣生する – TOSが無効な状況を認めると,実⾏行行時チェックが必要になる 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁28 解決法の例例:Stack  Caching 0x1234 0x5678 0x68AC SP SP iadd ハンドラ 0x1234 0x5678 0x68AC SP SP iadd ハンドラ 0x1234 TOSレジスタ 0x68AC TOSレジスタ Stack  Cachingなし Stack  Cachingあり
  • 29. ©  2016  IBM  Corporation § 効率率率よく,キャッシュ要素数を可変にする技術 § Step-­‐1:キャッシュしている要素数ごとに 別々のハンドラを⽤用意する 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁29 改良良:Dynamic  Stack  Caching  [Ertl’95] 0x5678 SP SP iadd (c1àc1) 0x1234 TOSレジスタ 0x68AC TOSレジスタ キャッシュ要素数=1 のハンドラの動作 SP SP iadd (c2àc1) 0x1234 TOSレジスタ 0x68AC TOSレジスタ 0x5678 NOSレジスタ キャッシュ 要素数=2 NOS: Next of Stack 0x1234 0x5678 SP SP iadd (c0àc1) 0x68AC TOSレジスタ キャッシュ要素数=0 のハンドラの動作 キャッシュ 要素数の変化
  • 30. ©  2016  IBM  Corporation § Step-­‐2:キャッシュしている要素数ごとに⽤用意したハンドラでステートマシンを構成して, キャッシュしている要素数を管理理 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁30 改良良:Dynamic  Stack  Caching  [Ertl’95] iadd (c0àc1) iadd (c1àc1) iadd (c2àc1) iconst_1 (c0àc1) iconst_1 (c1àc2) iconst_1 (c2àc2) ifeq (c0àc0) ifeq (c1àc0) ifeq (c2àc1) iload_3 (c0àc1) iload_3 (c1àc2) iload_3 (c2àc2) 例:「if (  x+1  ==  0  )」のハンドラ呼び出しフロー xをpush 1をpush 加算 TOS==0なら ジャンプ キャッシュ要素数=2 キャッシュ要素数=1 キャッシュ要素数=0
  • 31. ©  2016  IBM  Corporation § プロセッサ内部では,メモリの読み書きは常にワード境界に合わせた動作をする – ワード単位でない場合は,適宜エミュレートする § バイトコードの読み込みでは,同じワードを何度度も読込む 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁31 バイトコード読み込みのメモリアクセスの⾮非効率率率性 ff fa ??バイトコード 9d93741d 74 93 9d ff fa ワード境界 オペコード0x74を読込み オペコード0x93を読込み オペコード0x9dを読込み オペランド0xfffaを読込み 例:「while(  (short)(-­x)  >  0  );;」のデコード操作
  • 32. ©  2016  IBM  Corporation § しかし,バイトコード列列をワード単位でレジスタにキャッシュすると, バイトコードのワード内オフセットのチェックが必要になる 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁32 解決法の例例:バイトコードをワード単位でキャッシュ 例:「while(  (short)(-­x)  >  0  );;」のデコード操作 ff fa 1cバイトコード 9d93741d 74 93 9d ff fa ワード境界 オペコード0x74を読込み オペコード0x93を読込み オペコード0x9dを読込み オペランド0xfffaを読込み レジスタにキャッシュ ff fa 1c9d9374
  • 33. ©  2016  IBM  Corporation § オペコードのワード内位置ごとに,別々のバイトコード・ハンドラを⽤用意し, ステートマシンで現在のワード内位置を追跡する 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁33 改良良:Position-­‐based  handler  customization  [Ogata’02] ff fa 1cバイトコード 9d93741d ワード境界 レジスタにキャッシュ (Bytecode  Prefetch  Register) ff fa 1c9d9374 ineg (b0àb1) next  opcode =  BPR0[1] ineg (b1àb2) next  opcode =  BPR0[2] ineg (b2àb3) next  opcode =  BPR0[3] ineg (b3àb0) next  opcode =  BPR1[0] BPR0  =  BPR1 Load  BPR1 BPR0 BPR1 9374 BPR0 9374 BPR0 9374 BPR0 9374 BPR0 BPR1 例:ineg(0x74)ハンドラの4つのバリエーション
  • 34. ©  2016  IBM  Corporation SPECjvm 98 jBYTEmark JavaGrande 相対性能 § ベース・インタープリタ(Threaded  code)からの速度度変化 – DS=Dynamic  Stack  Caching,WT=Write-­‐throughで常に1個キャッシュ – PHC=ワード単位でバイトコードをキャッシュ,PSD=投機的にデコード 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁34 パフォーマンス⽐比較遅い←→速い ※ このグラフはゼロ始まりでないので注意 Java:  IBM  JDK  1.3.0 HW:  POWER3  400MHz,  768MB  Memory OS:  AIX  4.3.3 ※どの最適化がよく効くかは, プロセッサの特性によっても異異なる
  • 36. ©  2016  IBM  Corporation § Javaヒープ – Javaオブジェクトを格納する領領域 § オブジェクト管理理 – Javaでは,不不要になったオブジェクトは ガベージコレクタ(GC)が⾃自動回収する § オブジェクト管理理に関するトピック – オブジェクトの構造 – オブジェクトの⽣生成 – オブジェクトの回収(GC) – 関連する話題など 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁36 オブジェクト管理理 クラス管理 オブジェクト 管理 インタープリタ JIT コンパイラ JITコンパイラ 生成コード 実行時 プロファイラ クラスデータ (Java  バイト コード) Javaヒープ (Java  オブ ジェクト) Javaスタック (ローカル変数, オペランドスタック) Java仮想マシン(Java  VM) Java同期 ランタイム Java例外処理 ランタイム JVM ランタイム
  • 37. ©  2016  IBM  Corporation § オブジェクト指向⾔言語では,オブジェクトを⽣生成しメソッドを呼び出すことで処理理が⾏行行われる – オブジェクトはnewした時に「ヒープ」内に作られるが,ライブラリ内などで暗黙のうち に⽣生成されるオブジェクトもたくさんある § ⾮非常に単純なプログラムの例例 – ⼀一⾒見見オブジェクトなど使っていないようでも,オブジェクトが使⽤用されている 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁37 オブジェクトを⽤用いた処理理 1  class  SayHello { 2          static  String  str =  "Hello  ";; 3 4   public  static  void  main(String[  ]  args)  { 5     String  msg =  str +  args[0];; 6     System.out.println(msg);; 7         msg =  null;; 8  } } $  javac SayHello.java $  java  SayHello world Hello  world StringBuilder tmp =  new  StringBuilder();; tmp.append(str);; tmp.append(args[0]);; String  msg =  tmp.toString();; § ⾚赤字部分でオブジェクトが⽣生成される § オブジェクトの構造 – メタ情報が⼊入るヘッダ – フィールド値が⼊入るボディ String value offset=0 count=5
  • 38. ©  2016  IBM  Corporation § オブジェクトは,クラスで定義されたフィールドを持つ – 親クラスのフィールドも持つので,親クラスのインスタンスのふりができる § フィールドを保持する「ボディ」の他に,メタ情報を持つ「ヘッダ」がある – ヘッダには,クラスへのポインタ,配列列のサイズ,ロックやGCのための情報などがある § オブジェクトを指すには,直接指す⽅方法と,ハンドルを介す⽅方法がある – ハンドルを介すとオブジェクトの移動がしやすいが,性能とメモリ消費に影響がある – 現在の主流流は直接指す⽅方法 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁38 オブジェクトの構造 class  A  { char  c;; int i;; short  s;; } i s j a c s ヘッダ i s c ヘッダ Aのインスタンス Bのインスタンス ハンドルテーブル class  B  extends  A  { int j;; short  s;; A  a;; } 32bit
  • 39. ©  2016  IBM  Corporation § ハンドルの削除 – 最初はハンドルあり(低性能)+容易易なコンパクション – →  ハンドルなし+保守的GCによる限定的コンパクション – →  ハンドルなし+マップを⽤用意したtype  accurate  GC § ロックのためのデータ構造の⼯工夫 – 現在の同期機構では,ロックのためにヘッダ内の1ワード弱を使⽤用 [Bacon’98] – あまり同期に使⽤用されないクラスはロックワードを持たない [Bacon’02] § 同期に使⽤用された場合は外部に追加データを⽤用意して対処 è 現在のIBM  Javaでは,ヘッダは最少1ワード(クラスポインタ+フラグのみ) – 配列列の場合は,サイズを保持するために+1ワード – 「頻繁に同期に使⽤用される」クラスの場合は+1ワード § Compressed  References – 64bitマシンでも,ポインタを32bitに圧縮して保持 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁39 オブジェクト使⽤用メモリの削減 i s j a c s ヘッダ i s c ヘッダ Aのインスタンス Bのインスタンス ハンドルテーブル 32bit
  • 40. ©  2016  IBM  Corporation § オブジェクトを作る場所は,ヒープとしてメモリ空間上 に確保されている – ヒープ上の,オブジェクトに割り当てていない場所を フリーエリアやフリーリストとして管理理 – newが呼ばれると,フリーエリアからメモリを確保し オブジェクトを作る § マルチスレッド環境への対処 – 複数のスレッドが同時にnewを呼ぶことがあるため, ヒープからのオブジェクト領領域確保は排他的に⾏行行う必 要がある – しかしそれだと遅くなるので,スレッドごとにヒープ の⼀一部を割り当て(スレッドローカルヒープ),そこ からオブジェクトを割り当てるのが⼀一般的 – スレッドローカルヒープがなくなった場合,新しいも のをヒープから割り当てる(ここは排他制御が必要) 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁40 オブジェクトの⽣生成 Javaヒープ For Th1 For Th2 For Th1
  • 41. ©  2016  IBM  Corporation § SayHelloクラスの初期化 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁41 オブジェクトを⽤用いた処理理 ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘ ’ char[6]String value offset=0 count=6 str class  SayHello Javaヒープ 1  class  SayHello { 2      static  String  str =  "Hello  ";; 3 4      public  static  void  main(String[  ]  args)  { 5          String  msg =  str +  args[0];; 6          System.out.println(msg);; 7          msg =  null;; 8  }  } Stringオブジェクトの 内部構造は処理理系依存 であり,ここで⽰示して いるのは⼀一例例です.
  • 42. ©  2016  IBM  Corporation2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁42 オブジェクトを⽤用いた処理理 ‘w’ ‘o’ ‘r’ ‘l’ ‘d’ char[5] [0] String[1] String value offset=0 count=5 ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘ ’ char[6]String value offset=0 count=6 str args class  SayHello Thread  stack Javaヒープ 1  class  SayHello { 2      static  String  str =  "Hello  ";; 3 4      public  static  void  main(String[  ]  args)  { 5          String  msg =  str +  args[0];; 6          System.out.println(msg);; 7          msg =  null;; 8  }  } § スレッドスタックと引数argの⽤用意 Stringオブジェクトの 内部構造は処理理系依存 であり,ここで⽰示して いるのは⼀一例例です.
  • 43. ©  2016  IBM  Corporation § tmp =  new  StringBuilder(); 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁43 オブジェクトを⽤用いた処理理 ‘w’ ‘o’ ‘r’ ‘l’ ‘d’ char[5] [0] String[1] String value offset=0 count=5 ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘ ’ char[6]String value offset=0 count=6 ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘ ’ char[16] ‘w’ ‘o’ ‘r’ ‘l’ ‘d’ StringBuilder value count=0 str msg args tmp class  SayHello Thread  stack Javaヒープ 1  class  SayHello { 2      static  String  str =  "Hello  ";; 3 4      public  static  void  main(String[  ]  args)  { 5          String  msg =  str +  args[0];; 6          System.out.println(msg);; 7          msg =  null;; 8  }  } Stringオブジェクトの 内部構造は処理理系依存 であり,ここで⽰示して いるのは⼀一例例です.
  • 44. ©  2016  IBM  Corporation ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘ ’ char[16] ‘w’ ‘o’ ‘r’ ‘l’ ‘d’ 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁44 オブジェクトを⽤用いた処理理 ‘w’ ‘o’ ‘r’ ‘l’ ‘d’ char[5] [0] String[1] String value offset=0 count=5 ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘ ’ char[6]String value offset=0 count=6 ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘ ’ char[16] ‘w’ ‘o’ ‘r’ ‘l’ ‘d’ StringBuilder value count=11 str msg args tmp class  SayHello Thread  stack Javaヒープ 1  class  SayHello { 2      static  String  str =  "Hello  ";; 3 4      public  static  void  main(String[  ]  args)  { 5          String  msg =  str +  args[0];; 6          System.out.println(msg);; 7          msg =  null;; 8  }  } § tmp.append(str);  tmp.append(args[0]); Stringオブジェクトの 内部構造は処理理系依存 であり,ここで⽰示して いるのは⼀一例例です.
  • 45. ©  2016  IBM  Corporation § msg =  tmp.toString(); 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁45 オブジェクトを⽤用いた処理理 ‘w’ ‘o’ ‘r’ ‘l’ ‘d’ char[5] [0] String[1] String value offset=0 count=5 ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘ ’ char[6]String value offset=0 count=6 ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘ ’ char[16] ‘w’ ‘o’ ‘r’ ‘l’ ‘d’ String value offset=0 count=11 StringBuilder value count=11 str msg args tmp class  SayHello Thread  stack Javaヒープ 1  class  SayHello { 2      static  String  str =  "Hello  ";; 3 4      public  static  void  main(String[  ]  args)  { 5          String  msg =  str +  args[0];; 6          System.out.println(msg);; 7          msg =  null;; 8  }  } Stringオブジェクトの 内部構造は処理理系依存 であり,ここで⽰示して いるのは⼀一例例です.
  • 46. ©  2016  IBM  Corporation § msg =  null; 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁46 オブジェクトを⽤用いた処理理 ‘w’ ‘o’ ‘r’ ‘l’ ‘d’ char[5] [0] String[1] String value offset=0 count=5 ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘ ’ char[6]String value offset=0 count=6 ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘ ’ char[16] ‘w’ ‘o’ ‘r’ ‘l’ ‘d’ String value offset=0 count=11 StringBuilder value count=11 str msg args tmp class  SayHello Thread  stack Javaヒープ 1  class  SayHello { 2      static  String  str =  "Hello  ";; 3 4      public  static  void  main(String[  ]  args)  { 5          String  msg =  str +  args[0];; 6          System.out.println(msg);; 7          msg =  null;; 8  }  } Stringオブジェクトの 内部構造は処理理系依存 であり,ここで⽰示して いるのは⼀一例例です.
  • 47. ©  2016  IBM  Corporation § オブジェクトは使われなくなってもヒープに残る! 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁47 オブジェクトを⽤用いた処理理 ‘w’ ‘o’ ‘r’ ‘l’ ‘d’ char[5] [0] String[1] String value offset=0 count=5 ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘ ’ char[6]String value offset=0 count=6 ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘ ’ char[16] ‘w’ ‘o’ ‘r’ ‘l’ ‘d’ String value offset=0 count=11 StringBuilder value count=11 str msg args tmp class  SayHello Thread  stack Javaヒープ 1  class  SayHello { 2      static  String  str =  "Hello  ";; 3 4      public  static  void  main(String[  ]  args)  { 5          String  msg =  str +  args[0];; 6          System.out.println(msg);; 7          msg =  null;; 8  }  } Stringオブジェクトの 内部構造は処理理系依存 であり,ここで⽰示して いるのは⼀一例例です.
  • 48. ©  2016  IBM  Corporation § ⽣生成したオブジェクトは,不不要になったら消去しなければならない – そうしないと,ヒープがいっぱいになって処理理が続けられなくなる § C++では(デフォルトでは),deleteによりアプリが明⽰示的に消去する – 消去し忘れや,不不要でないのに消去してしまうなどの危険性がある – セキュリティーホールにもなりえる § Javaでは,ガベージコレクタ(GC)が標準装備されており, 不不要なオブジェクト(=ガベージ)は⾃自動的に回収(=コレクト)される 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁48 オブジェクトの回収
  • 49. ©  2016  IBM  Corporation2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁49 不不要なオブジェクトとは? ‘w’ ‘o’ ‘r’ ‘l’ ‘d’ char[5] [0] String[1] String value offset=0 count=5 ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘ ’ char[6]String value offset=0 count=6 str msg args tmp class  SayHello Thread  stack Javaヒープ ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘ ’ char[16] ‘w’ ‘o’ ‘r’ ‘l’ ‘d’ String value offset=0 count=11 StringBuilder value count=11 1  class  SayHello { 2      static  String  str =  "Hello  ";; 3 4      public  static  void  main(String[  ]  args)  { 5          String  msg =  str +  args[0];; 6          System.out.println(msg);; 7          msg =  null;; 8  }  } § GCルートからたどり着けないオブジェクトは不不要 7行目終了時点で 「死んで」いるオブジェクト GCルートの例例 – スレッドの実⾏行行スタック (ローカル変数) – クラスのスタティック変数 (グローバル変数) – などなど
  • 50. ©  2016  IBM  Corporation § ガベージコレクションの基本アルゴリズム(の⼀一つ) 1.  Stop  the  world – すべてのスレッド(Mutator)を⼀一時停⽌止させる(Stop-­‐the-­‐world) – GC中にオブジェクトの変更更を⾏行行わせないため 2.  Mark – GCルートからたどれるオブジェクト に「マーク」を付ける – マークが付いたオブジェクトは 「⽣生きて」いる(=回収できない) 3.  Sweep – マークが付いていないオブジェクト の領領域をフリーリストにつなぐ 4.  後処理理 – 停⽌止したスレッドの実⾏行行を再開 § 利利点:仕組みが単純 § ⽋欠点:GC中,アプリケーションが停⽌止 してしまう,停⽌止時間も⻑⾧長め 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁50 ガベージコレクションの基本:Mark  &  Sweep class SayHello Thread stack JavaヒープGCルート M M M M M
  • 51. ©  2016  IBM  Corporation § どのデータがオブジェクトを指しているの か? – たとえば,0x12345678というデータが ⼊入っていた場合,それはオブジェクト を指しているのか,単なる⼤大きなint値 なのか? § 処理理系は,オブジェクトやクラスがどうい う構造をしているのか知っている (Javaでは) – そのためGCは,オブジェクトを指す フィールドだけをたどることができる § スレッドスタックの処理理が問題 – どのエントリがオブジェクトを指して いるかがわからないといけない – スレッド停⽌止地点によっても変わる 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁51 Mark処理理とその注意点 class SayHello Thread stack JavaヒープGCルート M M M M M Mark処理 for (各GC Rootについて) GC Root内のオブジェクト参照の場所を「処理リスト」に足す while (処理リストに参照場所がある間) { 処理リストから参照場所を取り出す 参照先のオブジェクトがマーク済みなら次へ オブジェクトをマークする オブジェクト内の参照場所を処理リストに足す }
  • 52. ©  2016  IBM  Corporation § スタックフレームのどこに「オブジェクトへの参照」が⼊入っているか? – インタープリタ実⾏行行の場合は,Javaスタックのどのエントリがオブ ジェクト参照であるかは(基本的に)わかるのでそれを使う – JITコンパイルされたメソッドを実⾏行行している場合,ネイティブス タックを使うので,簡単にわからないことがある. § さらに,CPUレジスタからオブジェクトを指している場合もある § スレッドを⼀一時停⽌止させる時,上の情報がわかるポイント (GC  Safe  Point)でのみ停⽌止させる – この時同時にCPUのレジスタの内容もメモリに書き出す – 停⽌止した場所(プログラムカウンタ)から,スタックフレームのど の場所にオブジェクト参照があるかの「マップ」を引き,マーク処 理理を⾏行行う § そのようなマップを⽤用意するのは処理理系(JITコンパイラ)の責任 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁52 スレッドスタックのスキャン main のスタック フレーム methodX のスタック フレーム methodY のスタック フレーム msg args tmp ret o obj arg ret a b tmp ret p i i ある時点での スタックの例
  • 53. ©  2016  IBM  Corporation § GC  Safe  Pointの⽤用意 – 他のメソッドを呼び出す(新しいスタックフレームができる)地点は GC  Safe  Pointにしないといけない – ループしている部分は,その中にGC  Safe  Pointがないといけない § 通常,ループのバックエッジ部分をGC  Safe  Pointにする § GC  Safe  Pointでスレッドを停⽌止するには? – スレッド外から強制的に(pthread_killなどで)停⽌止させると,どこで停まるかわからない – 協調的なスレッド停⽌止機構が必要 § インタープリタやJITコンパイルされたコードは,GC  Safe  Pointの通過時にフラグを チェックして,停⽌止を要求されている場合は⾃自主的に停まる § この時同時にCPUのレジスタの内容もメモリに書き出し,動作再開時にCPUのレジス タに書き戻す 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁53 GC  Safe  Pointでのスレッド停⽌止
  • 54. ©  2016  IBM  Corporation § GC  Safe  Pointやマップが作れない場合の⽅方法 – ⾔言語処理理系の「助け」が不不要なGC⼿手法 – オブジェクトぽい値はオブジェクトを指していると考えて保守的にマークする § 「オブジェクトぽい」とは? =値が,割り当て中のオブジェクトの(先頭)アドレスと⼀一致している § ヒープのアドレスや,各オブジェクトの先頭アドレスはわかるという前提 – 初期のJava処理理系はこれ(Conservative  GC)を使っていた § 逆に,型情報が完全にわかる最近のGCは「Type-­‐Accurate  GC」とも呼ばれる § 利利点: – GC  Safe  Pointやマップを⽤用意しなくてもマーク処理理が⾏行行える § ⽋欠点: – 不不要であるはずのオブジェクトまでマークしてしまう危険性がある – 特に,使い終わったローカル変数などを積極的にクリアする必要がある – 保守的にマークされたオブジェクトは動かすことができない 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁54 Conservative(保守的) Marking
  • 55. ©  2016  IBM  Corporation § マークが付かなかったオブジェクトの領領域を フリーリストにつなぐ – 同時に,次のGCのためにマークをクリアする – 前後にフリー領領域がある場合は結合する(Coalescing) § マークをどこに置くか? ⽅方法1.  オブジェクトのヘッダに⼊入れる ⽅方法2.  別の場所にビット列列を⽤用意する § オブジェクトは8バイト単位でアラインされている ことなどを利利⽤用して圧縮可能 § ヒープ全体にアクセスが起こらないので,この⼿手法 が⼀一般的 § Sweep処理理を繰り返すうちに,フリー領領域が細切切れになっ てしまう危険性がある(Fragmentation) àオブジェクトをヒープ内で詰めなおして ⼤大きな連続フリー領領域を作るCompactionが必要 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁55 Sweep処理理とその注意点 Javaヒープ Sweep処理 for (割り当て中の各オブジェクト領域について) { if (マークが付いている) マークをクリアして次へ else { 領域をフリーリストにつなぐ(オブジェクトの回収) その際,前後にフリー領域がある場合は結合する } }
  • 56. ©  2016  IBM  Corporation § そのオブジェクトを指している参照をすべて移動先に書き換える必要がある – Conservativeに指されているオブジェクトは動かせないので注意が必要 § 参照元が本当にそのオブジェクトを指しているのか,ただの数値なのか判別がつかな いため § Compactionの⼀一⼿手法(Forwarding  Pointer法) 1. まず,⽣生きているオブジェクトの「移動先」 を決め,各オブジェクトのForwarding  Pointer に記録 2. 参照を「移動先」に書き換える 3. ⽣生きているオブジェクトを移動先に移動する § 利利点:Fragmentationの解消,使⽤用ヒープエリアの縮⼩小 § ⽋欠点:複数回の追加ヒープスキャンが必要 – そのため,Compactionは毎回のGCでは⾏行行わないことが多い – スキャンの少ないReverse  Pointer法などもある 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁56 Compaction処理理とその注意点 Compaction処理(Forwarding Pointer法) for (生きている各オブジェクトについて) 移動先を決め,オブジェクトのForwarding Pointerに記録 for (GC Root内と生きている各オブジェクト内の参照について) 参照を「移動先」に書き換える for (生きている各オブジェクトについて) オブジェクトを移動先に移動する
  • 57. ©  2016  IBM  Corporation § 多くのオブジェクトの寿命は短い – ⽣生成された後しばらく使われ, すぐに不不要になる à ヒープを「新世代オブジェクト⽤用の 領領域(nursery)」と「旧世代⽤用の領領域 (tenured)」に分ける – 新世代領領域はCopying  GC, 旧世代領領域はMark  &  Sweep  GC – Copying  GCを何回か⽣生き延びると,その オブジェクトは旧世代領領域に移される (Tenuring,殿堂⼊入り) § 旧世代から新世代を指す場合は, Remembered  Setに追加する § 利利点:GCによる停⽌止時間が短い(頻繁に⾏行行われる新世代領領域のGCについて) § ⽋欠点:Write  Barrier処理理(旧世代から新世代を指してないかのチェック) – スループットだけを考えるなら,単純なMark  &  Sweepの⽅方が⾼高い 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁57 その他のGC⼿手法:Generational  +  Copying  GC class SayHello Thread stack Javaヒープ(nursery1) GCルート Javaヒープ(tenured)Remem- bered Set Javaヒープ(nursery2)
  • 58. ©  2016  IBM  Corporation § ヒープをたくさんの「リージョン」に分割して管理理 – 各リージョンを,nurseryやtenured領領域として割り当てることができる 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁58 その他のGC⼿手法:Region  Based  GC Javaヒープ 未使用 Nursery (新規割当用) Nursery (生き残った オブジェクト) Tenured Nursery (生き残った オブジェクト) Tenured (巨大なオブ ジェクト用) Tenured 未使用 Tenured 未使用 未使用 未使用
  • 59. ©  2016  IBM  Corporation § 各オブジェクトについて,何箇所から指されているかのカウンタを管理理する – カウンタがゼロになったら回収する § オブジェクト参照を変更更する処理理で,カウンタのアップダウン処理理が必要 – たとえば,x.a =  y  という処理理では,オブジェクトyのカウンタを+1し,x.aが元々指していた オブジェクトzのカウンタを-­‐1する – zのカウンタが0になったら回収し,zが 指しているオブジェクトのカウンタも-­‐1 § 利利点:GCによる停⽌止時間がない – 死んだオブジェクトはすぐ回収可能 § ⽋欠点: – カウンタ操作が重い – すべてのオブジェクト書き込み ポイントにカウンタ処理理が必要 § 抜けがあるとヒープが壊れる – 循環参照が回収できない § そのため通常,Mark  &  Sweep と組み合わせて⽤用いられる 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁59 その他のGC⼿手法:Reference  Counting  GC class SayHello Thread stack Java heapGC Root 1 1 1 0 0 1 1 01 1 12
  • 60. ©  2016  IBM  Corporation § Incremental  GC  (Concurrent  GC) – Mutator(アプリの動作)と並⾏行行して,少しずつMark処理理を⾏行行う – オブジェクトを3⾊色に塗る(Tri-­‐coloring) § ⽩白:まだチェックしていないオブジェクト § 灰:チェック途中のオブジェクト,⽩白を指してもよい § ⿊黒:チェック済みのオブジェクト,⽩白を指してはいけない – 基本動作 § まずすべてを⽩白にし,GCルートからたどれるものを灰⾊色にする § 灰⾊色の先を灰⾊色にする,全部灰⾊色になったらそのオブジェクトは⿊黒にできる ここの処理理を「少しずつ」⾏行行える § 灰⾊色がなくなったら,⽩白のままのオブジェクトを回収して終わり – ⿊黒から⽩白を参照するのを防ぐためにWrite  Barrierが必要 § それが起きたら⿊黒オブジェクト(か⽩白)を灰⾊色にする – 利利点:GCによる⼀一回の停⽌止時間を減らせる § Parallel   GC – GC処理理(MarkやSweep)を,複数スレッドを⽤用いて並列列に⾏行行う – 利利点:GC処理理の⾼高速化 … などなど 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁60 その他のGC⼿手法
  • 61. ©  2016  IBM  Corporation § IBM  Java – Generational  +  Copying   +  Concurrent  +  Parallel  (default) – Parallel  Mark  &  Sweep (-­‐Xgcpolicy:optthruput) § HotSpot VM  /  OpenJDK – Parallel  +  Generational – “G1  Collector” § Region-­‐Based  GC 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁61 各⾔言語実装のGC § C++  (Boehm  GCライブラリ) – Conservative  Mark  &  Sweep § Ruby – Conservative  Mark  &  Sweep – “Restricted”  Generational  /   Incremental  GC § C-­‐Python – Reference  counting § PHP  (Zend) – Reference  counting § Swift – Reference  counting
  • 62. ©  2016  IBM  Corporation GC関連の話題いろいろ 62 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁
  • 63. ©  2016  IBM  Corporation § ⼀一般に,⾔言語がその⾔言語以外で書かれた(ネイティブな)処理理を実⾏行行できる場合,オブジェ クトを勝⼿手に操作されると正しいGCが困難になる – たとえば,ネイティブコードでオブジェクトを変更更するとWrite  Barrierの処理理が⾏行行えない – そもそも,ネイティブコードが使⽤用中のオブジェクトがわからないと回収してよいかも決 められない § Javaの場合,JNIインタフェースを使っていれば⼤大きな問題は⽣生じない – オブジェクトに対する操作は,すべてJNIインタフェースを通じて⾏行行われる § GetObjectField(env,  obj,  fid),SetObjectField(env,  obj,  fid,  obj)  など – オブジェクトのアドレスはネイティブコードには渡らない,「ハンドル」が渡される § そのようなオブジェクトは「表」に登録される,この表がGCルートとして扱われる – 配列列や⽂文字列列の⾼高速操作のために,アドレスを直接渡す場合だけ注意が必要 § GetPrimitiveArrayCritical(env,  array,  &isCopy)  は,Java配列列のアドレスをそのまま返せる が,ReleaseするまではGC  unsafeになる § JITコンパイルされたネイティブコードの扱い – JITコンパイラが,コンパイルしたコードにGC  Safe  Pointとマップを⽤用意する – 同時に,スレッドをGC  Safe  Pointで停⽌止させる仕組みも必要 § これらがない場合は,Conservative  GCになる 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁63 GC関連の話題:ネイティブコードへの対応
  • 64. ©  2016  IBM  Corporation § JavaにはString.intern()という処理理があり,同じ内容の⽂文字列列を⼀一つのオブジェクトにまとめる ことができる(インターン処理理) – 特に,リテラル⽂文字列列("Hello"  のようにプログラム中に直接書かれている⽂文字列列)は, 使⽤用時に⾃自動的にインターンされる § インターンされた⽂文字列列オブジェクトは,処理理系内部の「Intern  Table」に登録されている – 同じ⽂文字列列に対してString.intern()が呼ばれた場合に,既存のインターン済みオブジェクト にまとめるため § Intern  TableはGCルートではないが・・・ – インターンされた⽂文字列列オブジェクトが回収される場合,Intern  Tableから削除する処理理を 忘れず⾏行行わなければならない 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁64 GC関連の話題:String  Intern  Tableへの対応
  • 65. ©  2016  IBM  Corporation § Javaでは,オブジェクトが回収される時にfinalizeというメソッドを呼び出すことができる § GCではたとえば以下の処理理が必要 – Mark時に,finalizeメソッドを持つオブジェクトの先についてもMark処理理し, – Sweep時に,finalizeメソッドを持つオブジェクトは解放せず,「Finalizationキュー」につ なぐ § システム内の「Finalizerスレッド」が,キュー内のオブジェクトのfinalizeメソッドを順 に呼び出していく § finalize処理理により,オブジェクトが「⽣生き返る」こともある ※ finalizeメソッドが呼ばれるタイミングはすごく後になることもあるので, あまり使うべきではない(メモリリークの原因にもなりえる) 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁65 GC関連の話題:Finalizerへの対応
  • 66. ©  2016  IBM  Corporation § Javaでは,オブジェクトを「弱く参照(Weak  Reference)」することができる – 弱参照しかされていないオブジェクトはGCの対象になる – WeakHashMapなどで利利⽤用 § キーを弱参照で保持,キーが回収されるとHashMapからも消される – 弱参照は,WeakReferenceという特別なオブジェクトを通じて⾏行行う § 弱参照先が回収されると,ReferenceQueueに⼊入れられる § GCでは,GC後にWeakReferenceオブジェクトだけを再チェックし, 弱参照先が回収されていたらキューにつなぐ,などの⽅方式で実装できる – もしくは,マークに「⾊色」をつける(StrongなマークとWeakなマーク)など 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁66 GC関連の話題:Weak  Referenceへの対応
  • 67. ©  2016  IBM  Corporation § 特定の条件を満たすオブジェクトは,ヒープでなく スタック上に作ることも可能 – newしたメソッド内(以下)でしか使われない – 他のオブジェクトなどに代⼊入されない – これらの条件を満たすオブジェクトは メソッドから「Escapeしていない」と⾔言う § JITコンパイラが「Escape  Analysis」を⾏行行い, スタック上にオブジェクトを⽣生成するコードを出すことも可能 – スタックアロケートされたオブジェクトは,メソッド終了了時(スタックフレーム解放時) に⾃自動的に回収できる – ただしGC側でも,スタック上のオブジェクトを移動しないようにするなどの対応が必要 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁67 GC関連の話題:スタック上へのオブジェクト配置 String  concat(String  a,  String  b)  { StringBuilder  sb  =  new  StringBuilder();; sb.append(a);;  sb.append(b);; return  sb.toString();; } 上のStringBuilderオブジェクトはconcatメソッ ドからEscapeしていないので,(処理系がが んばれば)スタック上に配置することが可能
  • 68. ©  2016  IBM  Corporation § Javaアプリの性能が出ない場合,GCログをチェックするのが分析の第⼀一歩 § GC頻発の様々な要因(oはGC発⽣生地点) 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁68 GCログからの問題分析 (a)  健全な状態 (b)  長期オブジェクトが多すぎる (c)  メモリー・リーク (d)  短期オブジェクトができすぎる GC後のヒープ使用量 時間経過 最大ヒープ・サイズ GC発生ポイント
  • 69. ©  2016  IBM  Corporation § GCログを可視化し分析すると,たとえば以下のようなことがわかる – ヒープサイズは◯GBぐらい,Nurseryは◯GBぐらい – Minor  GCは◯秒に1回ぐらいのペースで起きている.つまり◯秒で◯GBぐらいアロケート している,毎分◯GBのペース – Minor  GCごとにちょっとずつオブジェクトがTenured領領域に逃げて⾏行行き,Major  GCを引き 起こしている – Major  GCが起きても回収できないものが少しずつ積みあがっていく(要するに何かがメモ リリークしている) – ヒープ使⽤用量量が少し下がるところ(最初以外)はcompactionが起きている,この compactionに◯秒ぐらいかかったあげく回収できるのがたった◯MBぐらい – Major  GCの頻度度はヒープが狭くなるとどんどん上がり,最終的には◯分に1回ぐらいに なっている 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁69 GCログからの問題分析:実例例
  • 70. ©  2016  IBM  Corporation Java:  IBM  J9  Java  VM  6.0  SR7  32bit HW:  Dual-­‐core  Opteron  2.4GHz  x2,  4GB  Memory OS:  SUSE  Linux  Enterprise  Server  10.0 § Java処理理系は,ヒープ以外にも意外とメモリを消費している 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁70 メモリの話題:ヒープ以外のメモリ消費 [Ogata’10] 0 50 100 150 200 250MB Malloc-­then-­freed   area=37MB Non-­Java   memory   size  by   category M.M.  overhead=6MB DLL=8MB JVM  work  area=42MB Class  area=87MB JITed  code=10MB JIT  work  area=18  MB Stack=4MB Java  heap 253MB +
  • 71. ©  2016  IBM  Corporation § Javaアプリでは,⽣生成されるオブジェクトの⼤大部分がStringオブジェクト – Stringオブジェクト内に,GCでは回収できないメモリの無駄がある § ライブヒープの40%は⽂文字列列保持のために⽤用いられているが,そのうち50%は無駄な領領域 – 25%  は重複した⽂文字列列 – 1%  はchar配列列内の使⽤用されない領領域 – 24%  は使⽤用されないリテラルデータ § これらはオブジェクト内の無駄なので従来のGCでは除去できない 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁71 メモリの話題:String⽤用メモリの無駄 [Kawachiya’08] 0 5 10 15 20 25 30 Trade6 MB dup unused literals String char[ ] other objects String memory inefficiencies (~20% of live heap) Live  heap   breakdown of  Trade6 Java:  IBM  J9  Java  VM  5.0  for  Linux App:  Trade6  benchmark  on  IBM  WAS  6.1 HW:  Xeon  3.06GHz  x2,  4GB  Memory OS:  Red  Hat  Enterprise  Linux  3  AS
  • 73. ©  2016  IBM  Corporation § Javaは,⾔言語⾃自体がスレッドによる並列列処理理を サポートしている § Java処理理系には,スレッド管理理のための仕組み に加え,スレッド間の排他制御を⾏行行うための 同期機構が必要 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁73 スレッドと同期 クラス管理 オブジェクト 管理 インタープリタ JIT コンパイラ JITコンパイラ 生成コード 実行時 プロファイラ クラスデータ (Java  バイト コード) Javaヒープ (Java  オブ ジェクト) Javaスタック (ローカル変数, オペランドスタック) Java仮想マシン(Java  VM) Java同期 ランタイム Java例外処理 ランタイム JVM ランタイム
  • 74. ©  2016  IBM  Corporation § Javaは⾔言語としてスレッドによる並列列処理理をサポートしている – java.lang.Thread – スレッドを作成する標準クラス – java.lang.Runnable – スレッドの処理理内容を記述するインタフェース § 商⽤用Java処理理系では,JavaスレッドはOSが提供するスレッド(たとえばpthread) にマッピングされ,OS⾃自⾝身によってスケジュールされることが多い – ネイティブメソッドからCコードやシステムコールを呼ぶ場合の親和性のため 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁74 スレッド処理理 class  MyRunnable implements  Runnable  { static  MyCounter c  =  new  MyCounter();; public  void  run()  { System.out.println("Hello  "  +  c.add(1));; } } Thread  t  =  new  Thread(new  MyRunnable());; t.start();;  // スレッドを実行開始 Java  thread JVM  thread (C/C++) pthread
  • 75. ©  2016  IBM  Corporation Javaは,⾔言語⾃自体がスレッドによる並列列処理理をサポートしている § スレッド間の同期はsynchronizedメソッドなどで指定される § モニタ⽅方式の排他制御 – たかだか1つのスレッドだけが当該オブジェクトのsynchronizedメソッドを実⾏行行できる – オブジェクトのロックが実⾏行行前に獲得され,実⾏行行後に解放される – ロックの再帰獲得や,イベント待ち合わせ(wait)と通知(notify)も可能 § Javaでは,以下の理理由によりロック処理理が頻繁に⾏行行われる – ライブラリは「スレッドセーフ」に作らなければならない – プログラマが容易易にロック処理理を指定できる (「synchronized」をつけるだけ) 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁75 Javaロック:スレッド間の同期機構 class  MyCounter { int value  =  0;; synchronized int add(int i)  { value  =  value  +  i;; return  value;; }      } MyCounter c1 add(1) add(1) add(1) value:10 MyCounter c2 value:5 Thread A Thread B Thread C
  • 76. ©  2016  IBM  Corporation § 背景:Java⾔言語の浸透 – 現在ではC,C++とならぶポピュラーな⾔言語 – サーバー環境では,ウェブサービス構築の必須⾔言語 – クライアント環境でも,Eclipseなどで不不可⽋欠 § 初期のJava⾔言語は処理理が⾮非常に遅かった・・・ – 機種独⽴立立なバイトコードを,Java仮想マシン(JVM)が実⾏行行する形式 à JITコンパイル技術の進歩により改善 – ランタイムシステムのオーバーヘッド à こちらは,JITによる⾼高速化が難しい § 初期の処理理系では,実⾏行行時間の2割近くを スレッド同期(ロック処理理)が占めていた à Javaアプリケーションの⾼高速実⾏行行に, ロック処理理の⾼高速化は不不可⽋欠 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁76 Javaロック⾼高速化の必要性 From  http://www.javaworld.com/jw-­03-­1998/jw-­03-­hotspot.html
  • 77. ©  2016  IBM  Corporation § Javaでは,ロックはオブジェクトを指定して⾏行行われる à 各オブジェクトヘッダにモニタ構造体を⽤用意する § 当然のことながら,メモリ使⽤用効率率率が悪い 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁77 Javaロックの超ナイーブな実装 Object 1 Header Body Monitor structure Object 2 Header Body Monitor structure Object 3 Header Body Monitor structure Object 4 Header Body Monitor structure Object 5 Header Body Monitor structure typedef struct object  { monitor_tmon;;   : }  Object;; int Java_lock_acquire(Object  *obj) {  return  monitor_enter(&obj-­>mon);;  } int Java_lock_release(Object  *obj) {  return  monitor_exit(&obj-­>mon);;  } int Java_lock_wait(Object  *obj) {  return  monitor_wait(&obj-­>mon);;  } int Java_lock_notify(Object  *obj) {  return  monitor_notify(&obj-­>mon);;  } int Java_lock_notify_all(Object  *obj){  return  monitor_notify_all(&obj-­>mon);;  } Javaロックの実装とは, これらのデータ構造と 関数を用意すること
  • 78. ©  2016  IBM  Corporation § 実際には,⼀一部のオブジェクト(せいぜい1割)しかロック処理理に⽤用いられないことを利利⽤用 à オブジェクトとモニタ構造体の関連付けをグローバルな表で管理理 § メモリ使⽤用効率率率は改善されたが, モニタ表の更更新・参照のためにグローバルロックが必要,スケーラビリティ低下 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁78 「モニタ表」を⽤用いたJavaロック実装 Object 1 Header Body Monitor table Object 2 Header Body Monitor structure Object 3 Header Body(no field for lock) Object 4 Header Body Object 5 Object 3 Monitor structure Object 5 Header Body Object 2 Monitor structure int Java_lock_acquire(Object  *obj)  { monitor_t*mon  =  lookup_monitor(obj);; return  monitor_enter(mon);; } int Java_lock_release(Object  *obj)  { monitor_t*mon  =  lookup_monitor(obj);; return  monitor_exit(mon);; }
  • 79. ©  2016  IBM  Corporation § オブジェクトヘッダ内の,あまり使⽤用されないフィールドの利利⽤用 à ロックに使⽤用された場合,そのフィールドから直接モニタ構造体を指す § 元々あったデータは,モニタ構造体の中に移動する § スケーラビリティは改善されたが, OSのモニタ機構をそのまま使っているため,依然として⾼高オーバーヘッド 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁79 Direct  Pointing⽅方式 [Onodera’98] Object 2 Header Body Object 4 Header Body rarely-used info 0 Object 1 Header Body rarely-used info 0 Monitor structure Object 3 Header Body 1 rarely-used info Monitor structure rarely-used info OBJFLAG_MON _ASSOCIATED Displaced info Object 5 Header Body 1 rarely-used info Monitor structure 1
  • 80. ©  2016  IBM  Corporation § Javaでは,多くのロックは衝突(contention)していないことを発⾒見見し活⽤用 à オブジェクトヘッダ内のロックワードを2つのモードで使⽤用する,bi-­‐modalロック § ロックが衝突するまでは,compare_and_swapでロック処理理を⾏行行う(Flatモード) § ロック衝突時にモニタ構造体を⽤用意し,以後はそれで処理理を⾏行行う(Inflatedモード) – 2つのモードは,ロックワード内のShapeビットにより区別される § 多くのロック処理理で重いモニタ機構が不不要になり, Javaアプリケーションの処理理性能が劇的に向上(元論論⽂文によれば「最⼤大1.7倍」) 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁80 Thinロック [Bacon’98  (Best  of  PLDI)] Object 2 Header Body Object 3 Header Body Object 4 Header Body Object 1 Header Body Lockword 0 1 0 0 T 0 0 Monitor structure Shape bit Object 5 Header Body 1 Monitor structure int Java_lock_acquire(Object  *obj)  { if  (compare_and_swap(&obj-­>lockword,   0,  thread_id())  ==  SUCCESS) return  SUCCESS;; :
  • 81. ©  2016  IBM  Corporation Javaロックのさらなる⾼高速化 81 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁
  • 82. ©  2016  IBM  Corporation § Thinロックにおけるロックワードの状態遷移 – compare_and_swap命令令1つでロック獲得,単純なストア命令令でロック解放が可能 § モード遷移に関する2つの(潜在的な)問題 – インフレーション(FlatモードからInflatedモードへの遷移)にビジーウェイトを使⽤用 – デフレーションが無い.⼀一旦衝突が起きたロックは,以後Inflatedモードで処理理される 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁82 Thinロックの(潜在的な)問題点 Object 1 Header Body Lockword 0 0 T0 1 00 releaseacquire Shape bit Monitor structure inflate Flat mode (Shape bit=0) Inflated mode (Shape bit=1) Object creation (pointer) Acquired by T Not acquired acquire / release
  • 83. ©  2016  IBM  Corporation § 各オブジェクトのロック衝突状況を,以下の指標を⽤用いて調査する – Flatセクション―  ロックが衝突していない状態 – Fatセクション ―  ロック獲得(もしくはイベント通知)を待っているスレッドがいる状態 § 結果:イベント待ち合わせに使われていないオブジェクトでは,衝突は⼀一時的な現象である – Javaロックの「衝突の⼀一時性」,要するにObject  3のようなケースが多い 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁83 Javaロックの衝突に関する挙動調査 Created Garbage collected Object 1 Created Garbage collected Object 2 Created Garbage collected Object 3 Flatセクション(ロックが衝突していない) Fatセクション (ロック獲得またはイベント通知を待っているスレッドがいる) Time
  • 84. ©  2016  IBM  Corporation § たすきロックにおけるロックワードの状態遷移 § デフレーションのサポート( 「衝突の⼀一時性」の活⽤用) – 衝突が解消すると,ロックワードをFlatモードに戻す § インフレーション制御のために,オブジェクトヘッダに1ビットのフラグを追加 – FLC(Flat  Lock  Contention)ビット ―  Flatモードでのロック衝突を⽰示す – ビジーウェイトを排除 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁84 たすきロック [Onodera’99] T0 1 00 releaseacquire Shape bit Monitor structure Flat mode (Shape bit=0) Inflated mode (Shape bit=1) Object creation (pointer) Acquired by T Not acquired acquire / release deflate & release inflate Object Body Shape bit FLC bit Header 0 T 0
  • 85. ©  2016  IBM  Corporation 1 2 3 4 5 6 7 8 9 10 # Terminals 0 5 10 15 Throughput (x1000 tpm) IBM116 Ours +11.4% +8.29% +13.1% +8.27% § Ibenchベンチマーク – トランザクション処理理をエミュレート,ターミナル数 m  を変えて測定する § たすきロックにより最⼤大13.1%の性能向上を確認 – さらに,マルチスレッド環境での性能低下を抑制 – ロック処理理の98%以上がFlatモードで⾏行行えている(Thinロックでは74%) Thin  lock Tasuki 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁85 実アプリでの性能⽐比較 遅い←                                →  速い IBM  JDK  1.1.6(Thinロックが採 用されている)に,たすきロックを 実装して測定した結果 たすきロック Thinロック Java  IBM  JDK  1.1.6 App:  Ibench benchmark HW:  PowerPC  604ev  166MHz,  128MB  Memory OS:  AIX  4.1.5
  • 86. ©  2016  IBM  Corporation § たすきロックにより,衝突がない状況ではわずか数命令令でロック処理理が可能になった § しかし,compare_and_swapなどの不不可分命令令が依然として必要 – 他者のJavaロック⼿手法でも同様の状況 – 不不可分命令令は⾮非常に重い命令令である à ロックのfastest  pathから,不不可分命令令をなくせないか? § たとえば・・・ オブジェクトが特定のスレッドによってのみ頻繁にロックされているなら, そのスレッドのロック処理理に限り不不可分命令令を無くせないか? ―  Javaロックの「スレッド局所性」 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁86 さらなる⾼高速化の可能性は? オブジェクト ヘッダ部 ボディ部 0 tid rcnt ロックワード compare_and_swapで スレッドIDを書き込む ことで,ロックを獲得 生成 消滅C C C C C BC CC スレッドCがロック スレッドCが頻繁にロックしている オブジェ クト
  • 87. ©  2016  IBM  Corporation § Javaロックの「スレッド局所性」を活⽤用 – オブジェクトを最初にロックしたスレッドが,ロックを「予約」できる à そのスレッドが引き続きロックを⾏行行った場合のコストを下げられる § 予約ロックにおけるロック獲得処理理 1. そのスレッドが予約を持っていた場合,不不可分命令令なしの⾼高速処理理を⾏行行う 2. 他のスレッドが予約を持っていた場合,まずその予約を「解除」する 3. 予約がすでに解除されていた場合,従来の⽅方式(たとえば たすきロック)で処理理を⾏行行う 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁87 予約ロック [Kawachiya’02] 1. この部分が高速化される 生成 消滅 オブジェ クト C C C C C BC CC 0. スレッドCに予約が与えられる 2. 予約が解除される 3. この部分は従来方式で処理される
  • 88. ©  2016  IBM  Corporation 1T 0 Reserved for Thread T 0 0 Anonymously reserved Acquired by T unreserve acquire release acquire release 1 Object creation 1T 1 1T 2 unreserve unreserve 0 0 0 : : Base lock algorithm Recursively acquired : : Reserve mode (LRV=1) Base mode (LRV=0) xxxxxx yyyyyy zzzzzz acquire (initial synchronization) LRV bit § ロックワードの状態遷移 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁88 予約ロックの動作 tid rcnt LRVビット 1 再帰カウンタ スレッドID § 予約スレッドは,rcntフィー ルドを単純に増減することで ロックの獲得と解放が⾏行行える (不不可分命令令は不不要) § 別のスレッドがロック獲得 を試みた時点で,予約は 「解除」される § 解除後は,従来⼿手法により 処理理が⾏行行われる – 複雑なケースはすべて 従来⼿手法に任せられる
  • 89. ©  2016  IBM  Corporation § 予約ロックでは,予約解除のコストが⾼高かった – 予約を保持しているスレッドを外部から強制停⽌止させる必要があるため – さらに,停⽌止した地点がロック処理理中(unsafe  region)であった場合,再開地点を移動す る必要もあった à 協調的スレッドスケジューリングを利利⽤用した改善 – スレッドを「GC  Safe  Point」で停⽌止させる仕組みを,予約解除時のスレッド停⽌止にも利利⽤用 メリット1. 予約解除の際の予約スレッド停⽌止にシステムコールが不不要であるため軽い メリット2. unsafe  regionで停⽌止することがないので停⽌止後コンテクストをチェックする 必要がない メリット3. 予約解除のコストが低いので,予約解除の頻度度等に応じて再予約も⾏行行える メリット4. synchronizedセクション内にGC  safe  pointがない場合は,予約時のロック処理理 から再帰カウンタの上げ下げすら省省略略できる § IBM  Javaでは,-­‐XlockReservation オプションで使⽤用可能 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁89 改良良版予約ロック [Grcevski’07]
  • 90. ©  2016  IBM  Corporation § Apache  Sparkでの性能改善 – TPC-­‐Hを実⾏行行した場合,22のうち7つのQueryで10%以上の改善(最⼤大18%) 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁90 予約ロック(改良良版)の効果 出典: http://www.spark.tc/reserve-­locks-­spark-­performance Java:  IBM  J9  Java  VM  Version  8  SR1  FP10 App:  TPC-­‐H  with  Spark  SQL  on  Spark  1.4.1,  with  100GB  dataset HW:  POWER8  3.3GHz  x2  (total  24cores),  1TB  Memory OS:  Ubuntu  Linux  14.10
  • 91. ©  2016  IBM  Corporation § Escape Analysisの活⽤用 [Whaley’99など] – あるスレッドで⽣生成したオブジェクトが,そのスレッド以外には⾒見見えないことを解析する – Escapeしていないオブジェクトは,スタック上に配置したり,ロック処理理を省省略略できる § Transactional  Memory的⼿手法の活⽤用 [Nakaike’10][Odaira’14] – スレッドは全員synchronizedセクションを投機的に実⾏行行できる – synchronizedセクションを抜けるときに,変更更内容をメモリに書き戻す § ただし,競合があった場合はやりなおしになる § いずれも,JITコンパイラなどによるコード解析が必要 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁91 その他の改善⼿手法:ロック除去
  • 93. ©  2016  IBM  Corporation § 例例外の処理理 § 例例外処理理のコスト 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁93 例例外処理理 クラス管理 オブジェクト 管理 インタープリタ JIT コンパイラ JITコンパイラ 生成コード 実行時 プロファイラ クラスデータ (Java  バイト コード) Javaヒープ (Java  オブ ジェクト) Javaスタック (ローカル変数, オペランドスタック) Java仮想マシン(Java  VM) Java同期 ランタイム Java例外処理 ランタイム JVM ランタイム
  • 94. ©  2016  IBM  Corporation § try-­‐catch – tryブロックのコード範囲でthrowされた例例外に対し,catchブロック(例例外ハンドラ)を 定義する構⽂文 – 各catchブロックは、指定する例例外クラス(およびその⼦子クラス)の例例外を処理理する – finallyは,tryブロックの終了了時に必ず実⾏行行される 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁94 例例外の基本動作 try { canThrowE1();;  //  例外E1を投げるかもしれないメソッド }  catch (E1  e)  { //  例外E1が起きた時のハンドラ }  catch (E2  e)  { //  例外E2が起きた時のハンドラ }  finally { //  tryブロック終了時に(例外の有無にかかわらず)実行するコード }
  • 95. ©  2016  IBM  Corporation § バイトコードに「例例外表」がついている – 「 [0,3)の範囲で例例外E1が起きた場合, 6へ⾶飛ぶ 」 à § 例例外が発⽣生すると, – 例例外表をチェックし,ハンドラがあればそこへジャンプ – ハンドラがなければ,スタックを⼀一段巻き戻し,同様の処理理を⾏行行う § synchronizedブロックでロックを取得している場合,javacがfinally節相当のエントリを⽣生成し その中でアンロック(monitorexit)処理理を⾏行行うので,ランタイムでは特別な対処は不不要 – synchronizedメソッドの場合は,スタック巻き戻し時にランタイムがアンロックを⾏行行う 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁95 例例外の処理理 try { canThrowE1();; }  catch (E1  e)  { //例外E1が起きた時のハンドラ } Code: 0:  invokestatic #4  //  Method  canThrowE1 3:  goto 7 6:  astore_0 7:  return Exception  table: from        to    target   type 0          3          6       Class  E1
  • 96. ©  2016  IBM  Corporation § 例例外表を内側からチェックする 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁96 ネストしたtry-­‐catch try  { m1();; try  { m2();; try  { m3();; }  catch  (E3  e)  { _m3();; } }  catch  (E2  e)  { _m2();; } }  catch  (E1  e)  { _m1();; } Exception  table: from        to    target type 6          9       12 Class  E3 3        16        19 Class  E2 0        23        26 Class  E1
  • 97. ©  2016  IBM  Corporation 1. 例例外オブジェクトのnew 2. 例例外オブジェクトの<init>の呼出し – コールスタックの記録オブジェクトのnew – コールスタックのトレース 3. 例例外をthrow 4. 例例外ハンドラのサーチ – コールスタックの巻き戻し – 各フレームから例例外表を取得 – 例例外表で,プログラムカウンタに該当するtryを識識別 – tryにひもづいた例例外ハンドラの各候補に対し、現在の例例外クラスを扱えるかテスト (instanceofと同等の処理理) 5. 例例外ハンドラから実⾏行行を再開 à改善策:プロファイリングでthrowとcatchのペアを⾒見見つけ, JITコンパイル時に処理理してしまう [Ogasawara’01] 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁97 例例外処理理のコストと改良良
  • 99. ©  2016  IBM  Corporation § バイトコードを実⾏行行時(Just-­‐In-­‐Time)にコン パイルし,⾼高速実⾏行行する – 実⾏行行時プロファイラを⽤用いて,JITコンパイ ラによる最適化に有益な情報を収集するこ とも可能 § インタープリタの役割 – どのメソッドをJITをコンパイルするか決定 – JIT前にシンボルの解決(Resolve)などを なるべく済ませる – プロファイリング,統計情報収集など § 詳細はこの次の講演にて 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁99 JITコンパイラ(さわりだけ) クラス管理 オブジェクト 管理 インタープリタ JIT コンパイラ JITコンパイラ 生成コード 実行時 プロファイラ クラスデータ (Java  バイト コード) Javaヒープ (Java  オブ ジェクト) Javaスタック (ローカル変数, オペランドスタック) Java仮想マシン(Java  VM) Java同期 ランタイム Java例外処理 ランタイム JVM ランタイム
  • 100. ©  2016  IBM  Corporation § Javaバイトコードが実⾏行行される時に,そのバイトコードをコンパイルするコンパイラ – ⼀一般的には,メソッド単位(+インライニング)でコンパイルを⾏行行う 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁100 Java  Just-­‐in-­‐Time  (JIT)コンパイラ public  class  Hello  { public  static  void  main(String[]  args)  { System.out.println("Hello");; … Hello.java (ソースコード) public  static  void  main(java.lang.String[]);; Code: 0:  getstatic 3:  ldc … Hello.class (バイトコード) javac Hello.java(実⾏行行前に⾏行行う) main: ld st … ネイティブコード (マシンコード) JITコンパイル(実⾏行行中に⾏行行う) これはJITでは ないので注意 Java仮想マシン の守備範囲
  • 101. ©  2016  IBM  Corporation § バイトコードのポータビリティ(Write  Once  Run  Anywhere)維持のため – 実⾏行行時に各プラットフォーム向けのバイナリを⽣生成 § 実⾏行行時(プロファイル)情報を最適化に使うため – メソッドの呼び出し頻度度等 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁101 なぜJIT(実⾏行行中に)コンパイルするのか? public  class  A  { public  void foo()  {…} } public  class  B  extends  A  { public  void  foo()  {…} } public  class  C  extends  A  { public  void  foo()  {…} } public  void  bar  (A  a)  { … a.foo();; … } クラスA,  B,  Cの3つのfooメソッドが呼び 出される可能性があるが,頻繁に呼び出 されるメソッドをインラインしたい
  • 102. ©  2016  IBM  Corporation JITコンパイルの⼿手順 102 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁 public void foo() Code: 0: getstatic 3: ldc … public void bar() Code: 0: getstatic 3: ldc … public void zoo() Code: 0: getstatic 3: ldc … インタープリタ 1.  最初はバイトコードをインタープリタ実⾏行行 JITコンパイラ foo: ld st … bar: ld st … zoo: ld st … 2.  呼び出し回数が閾値を越えたメソッド に対してJITコンパイルリクエスト 3.  バイナリコードを⽣生成しプロセッサ上で直接実⾏行行
  • 103. ©  2016  IBM  Corporation § 各メソッドの性能に与える影響(=全実⾏行行時間に占める割合,method  hotness)に応じて 最適化レベルを変更更 – よく使われるメソッドは,より時間をかけて⾼高度度に最適化する 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁103 適応的コンパイル(Adaptive  Compilation) インタープリタ実行 低最適化レベルでのコンパイル 実行時間のプロファイル 高最適化レベルでのコンパイル § IBM  Java  JITコンパイラは6段の最適化 レベルを使⽤用 scorching veryHot hot warm  (最初の最適化レベル) cold noOpt 高 低
  • 104. ©  2016  IBM  Corporation § メソッドを定期的にサンプリング – サンプリングスレッドが定期的にアプリケーションスレッドの「フラグ」をセット – アプリケーションスレッドは,フラグがセットされたときに実⾏行行していたメソッドを サンプリング § フラグチェックは,GC  Safe  Pointで⾏行行う – メソッドの⼊入り⼝口,メソッドの出⼝口,ループの最後など – もともとGCのために⽤用意されているため,オーバヘッドにならない 2016/09/06 Java仮想マシンの実装技術 / 河内⾕谷清久仁104 メソッドの実⾏行行時間のプロファイル サンプリングスレッド サンプリングインターバル(e.g.  10ms) アプリケーションスレッド1 アプリケーションスレッド2 フラグセット メソッドAを実行 samples(A)++ メソッドBを実行 samples(B)++ public  void  foo()  { check();; for  (…)  { s  +=  a[i];; check();; } check();; }