超先取りShenandoahGC
- 12. BrookPointer+ライトバリア+CAS
① ② ③ ④
Java
スレッド
0
0
0
0
0
0
0
0
0
0
0
0
+1したい
GCスレッドが先に
BrooksPointerを切り替
え
JavaスレッドもBrooksPointerを切
り替えようとするが、
BrooksPointerが変更されているた
めCASが失敗する
そのままBrooksPointerの参
照を辿って更新処理をすれ
ばOK
まだBrooksPointerは切り
替えられていないので
Javaスレッドはコピーを
作成する
1
- 13. BrookPointer+ライトバリア+CAS(逆)
① ② ③ ④
Java
スレッド
0 0
0
0 0
0
0 1
0
0 1
0
+1したい
Javaスレッドが先に
BrooksPointerを切り替
え
Javaスレッドがオブジェクトを
更新
GCスレッドが
BrooksPointerを切り替えよ
うとしてもCASで失敗する
まだBrooksPointerは切り
替えられていないので
Javaスレッドはコピーを
作成する
- 14. ShenandoahGCのログ
Pause Init-Mark (2.346s, 2.347s) 0.274ms
Concurrent marking 12M->12M(16M) (2.347s, 2.348s) 1.590ms
Pause Final Mark 12M->4M(16M) (2.348s, 2.351s) 2.599ms
Concurrent evacuation 4M->5M(16M) (2.351s, 2.351s) 0.155ms
- 16. ShenandoahGCの流れ
Pause Init-Mark (2.346s, 2.347s) 0.274ms
Concurrent marking 12M->12M(16M) (2.347s, 2.348s) 1.590ms
Pause Final Mark 12M->4M(16M) (2.348s, 2.351s) 2.599ms
A
CB
ConcurrentMark中に変更されたヒープの状
態を反映して、生存オブジェクトが確定する
。
確定したら、ごみの量に基いてコレクション
セット(退避対象となるリージョンの集合)
が決定される
- 17. ShenandoahGCの流れ
Pause Init-Mark (2.346s, 2.347s) 0.274ms
Concurrent marking 12M->12M(16M) (2.347s, 2.348s) 1.590ms
Pause Final Mark 12M->4M(16M) (2.348s, 2.351s) 2.599ms
Concurrent evacuation 4M->5M(16M) (2.351s, 2.351s) 0.155ms
A
CB
A’ コレクションセット内の生存オブジェクトを
空きリージョンに退避させる。
GCスレッドが退避させる前にアプリケーショ
ンによる更新が行われた場合は、Javaスレッ
ドが退避を実行する。
- 18. ShenandoahGCの流れ
A
CB
A’
Pause Init-Mark (2.346s, 2.347s) 0.274ms
Concurrent marking 12M->12M(16M) (2.347s, 2.348s) 1.590ms
Pause Final Mark 12M->4M(16M) (2.348s, 2.351s) 2.599ms
Concurrent evacuation 4M->5M(16M) (2.351s, 2.351s) 0.155ms
Pause Init-Mark (2.926s, 2.928s) 1.869ms
Concurrent marking 12M->12M(16M) (2.928s, 2.932s) 3.416ms
次のGCのマークフェイズで、辿っている参照
がコレクションセット内のオブジェクトを指し
ていたら、マークついでに退避先に参照を切り
替える。
- 19. ShenandoahGCの流れ
A
CB
A’
Pause Init-Mark (2.346s, 2.347s) 0.274ms
Concurrent marking 12M->12M(16M) (2.347s, 2.348s) 1.590ms
Pause Final Mark 12M->4M(16M) (2.348s, 2.351s) 2.599ms
Concurrent evacuation 4M->5M(16M) (2.351s, 2.351s) 0.155ms
Pause Init-Mark (2.926s, 2.928s) 1.869ms
Concurrent marking 12M->12M(16M) (2.928s, 2.932s) 3.416ms
Pause Final Mark 12M->9M(16M) (2.932s, 2.933s) 1.205ms
マークが完了した時点で前回選択されたコレクシ
ョンセットへの有効な参照はなくなっているので
、リージョンのメモリを解放することができる。
マークの情報を使って、新しいコレクションセッ
トが選択される。
ログからもFinalMark のタイミングでメモリ使用
量が減っていることが読み取れる。
- 20. non-generational GC
❖ 世代別GC
➢ 一部領域をGCする際に経験則に基いて行う
➢ 「最近アロケーションした領域をGCしたほうが回収効率が良いだろう」
❖ Shenandoah では FinalMark 時点でヒープ内の全てのオブジェクトの
生存状況が把握できている
❖ どのリージョンを回収すればよいかを考える際、仮説に基づく必要はない
ShenadoahGC は世代別GCではない
❖ 世代別仮説にあてはまらないケースでも安定して動作する
❖ RememberedSet を持つ必要がない
❖ GCするたびにヒープ全体をマークする必要がある
- 22. おまけ(FAQ)
❖ ShenandoahGC は試せますか?
→ Shenandoahのソースコード(JDK9)を mercurial から持ってきてビルドすれば、あとは
-XX:+UseShenandoahGC オプションで利用できます。
ただし開発中なのでどのプラットフォームでも安定してビルドできるというわけではなかったりします。
今回はCentOS7の最新でうまくビルドできたので、うまくいかない場合はRedhat系ディストリビューショ
ンの最新版で試すのが良さそうです。
❖ ShenandoahGC の開発は進んでますか?
→ 2016年の後半は開発メンバーも増え、メーリングリストでのやりとりも活発でした。ソースコードを読
んでいても半年でずいぶんちゃんとしたなという印象です。一方でまだクリティカルなバグが普通に発生
したり、未実装の機能があったり(ex. ヒープダンプ出せません)するので、Production まではもう少しかか
りそうです。
❖ 色々処理が追加されているのでオーバーヘッドがあるのでは?
→ RememberedSetをなくしたというプラスはあるのですが、BrooksPointerもライトバリアもCASも少な
からずオーバーヘッドがあります。2016年はじめに開発主要メンバーのRomanさんが試してみたところ
だと、G1にはちょっと負けているようです(ポーズタイムはShenandoahの方がずっと短い)。
(参考)
https://rkennke.wordpress.com/2016/02/08/shenandoah-performance/