concurrent mark&sweep 第 6 回 jvm ソースコードリーディングの会 (openjdk)
DESCRIPTION
Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK). 中村 実 [email protected] [email protected] Twitter @nminoru_jp. Parallel GC と Concurrent GC. Stop the world(STW) 型 GC Java スレッド ( Mutator ) を止めてから GC Parallel GC は STW した後の GC 処理を複数のスレッドが分担 Concurrent GC - PowerPoint PPT PresentationTRANSCRIPT
![Page 2: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/2.jpg)
Parallel GC と Concurrent GC• Stop the world(STW) 型 GC
– Java スレッド (Mutator) を止めてから GC– Parallel GC は STW した後の GC 処理を複数のスレッドが分担
• Concurrent GC– Java スレッドと GC スレッドが同時に動く
Java threads
GC threads
GCParallel GC
Java threads
GC threads
Concurrent GC
![Page 3: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/3.jpg)
Concurrent GC
• メリット– Java が常に動けるので GC による停止がな
い。• デメリット
– 機構が複雑になり、 Java スレッドと GCスレッドが邪魔しあうのでスループット性能が落ちる。
![Page 4: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/4.jpg)
Hotspot VM の Concurrent GC
• Mostly Concurrent Mark & Sweep(CMS)– ほとんど concurrent だが一部停止する GC– Tony Printezis, David Detlefs. A Generational
Mostly-concurrent Garbage Collection (ISMM 2000)
4
Java threads
GC threads
GCMostly Concurrent GC
![Page 5: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/5.jpg)
CMS
• Mark&Sweep– Marking phase
• Concurrent marking• Serial marking(Hotspot VM の用語で final
marking)– Sweeping phase
• Concurrent sweeping
5
![Page 6: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/6.jpg)
Concurrent Marking(1/3)• Marking thread は root から初めてオブジェクトを巡回しマー
キングする ( 着色したオブジェクトはマークをあらわす )• Java スレッドはその間も動いて、オブジェクトを生成・参
照の変更を行う。
6
RootHeap
12 3
4
5
![Page 7: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/7.jpg)
Concurrent Marking(2/3)• Marking thread と Java スレッドが同時に動くと衝突が発生
– (A) 余分なマーク• 3 をマークし後に 2→3 の参照が切れた。
– (B) マーク漏れ• 1 をマークした後に 6 が作られた。
• (A) は GC が回収する量が減るだけだが、 (B) は許されない。
7
RootHeap
12 3
4
5
6
(A)
(B)
![Page 8: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/8.jpg)
Concurrent Marking(3/3)
• Write barrier– Java スレッドが putfield/putstatic などを実行した
時に、その reciever にライトバリアを付ける。(A.field = B なら A にライトバリア )
• Serial marking– Concurrent marking の後に STW を起こしてライト
バリアがついている場所から残りの marking を行う。
8
![Page 9: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/9.jpg)
9
OpenJDK での CMS の実装
![Page 10: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/10.jpg)
10
OpenJDK の GC の種類オプション ヒープのクラス 空間のクラス
逐次 GC -XX:+UseSerialGC GenCollectedHeap DefNewGenerationTenuredGeneration
並列 GC -XX:+UseParNewGC GenCollectedHeap ParNewGenerationTenuredGeneration
並列 GC -XX:+UseParallelGC ParallelScavengeHeapコンカレントGC
-Xconcgc or-XX:+UseConcMarkSweepGC
GenCollectedHeap ParNewGenerationConcurrentMarkSweep
インクリメンタル GC
-Xincgc( コンカレント GC に -XX:+CMSIncrementalMode をつけたもの )
GenCollectedHeap 同上
G1GC -XX:+UseG1GC G1CollectedHeap
![Page 11: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/11.jpg)
11
CMS のオプションオプション 説明
-Xconcgc or-XX:+UseConcMarkSweepGC
Concurrent GC を有効にする。
-XX:ConcGCThreads=<n> Concurrent GC スレッド数を指定する。デフォルトは 0 で Concurrent GC スレッドは 1 となる。
-XX:+CMSParallelRemarkEnabled CMS Full GC をマルチスレッドで実行する。マルチ CPU 環境ではデフォルトで指定される。
-XX:CMSWaitDuration=<n> 同期型の GC が起きた後に <n> ミリ秒経った後に CMSを開始する。デフォルトは 2000 ミリ秒。
-XX:+PrintGC-XX:+PrintGCDetails
GC の詳細を表示する。
-XX:+TraceCMSState Concurrent Mark&Sweep に関係する出力を増やす ( デバッグ版のみ ) 。
hotspot/src/share/vm/runtime/globals.hpp に多数存在。
![Page 12: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/12.jpg)
Hotspot VM の CMS の概要
• ConcurrentMarkSweepThread スレッドが全体を制御
• ヒープ空間は新旧 2 世代• Write barrier は Card marking で代替• CMS のマーキングはビットマーキング
12
![Page 13: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/13.jpg)
13
ヒープ構成
• 空間配置– 新世代は ParNewGC(parallel copying
GC) 用。– 旧世代は CMS 用でフリーリスト管理
されている。• GC
– 最初に新世代に ParNewGC を起こす(STW 型 )
– 次に旧世代に CMS GC を起こす。– それでも不足の場合は CMS Full GC
を起こす (STW 型 )
Perm
Old Gen.
Eden
From To
![Page 14: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/14.jpg)
14
Card Making の流用• Concurrent marking のためにはライトバ
リアが必要。でも世代別 GC には似たような処理があるので流用
• Card Table– 512 バイト単位に 1 バイトのバイトテーブル– Clean card は 0xFF 、 dirty card は 0– 本来は旧世代から新世代を指すオブジェク
トの位置を記録• putfield/putstatic/aastore にフック
– A.field = B 実行時になら
Old Gen.
New Gen.
B
Car
d Ta
ble
A dirty
clea
n
CardTableModRefBS::byte_map_base [uintptr_t(A) >> CardTableModRefBS::card_shift] = 0
![Page 15: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/15.jpg)
CMS GC と ParNewGC の競合• マーキング領域
– CMS のマーキングは専用のビットマップを使う(CMSBitMap) ので問題なし。
• GC– ConcurrentMarkSweepThread スレッドが動いている最中に
ParNewGC が起きることがある。その場合は ConcurrentMarkSweepThread が一時停止してから再開する。
15
Java threads
Conc GC thr
ParNew GC
Parallel GC thr
CMS GC
![Page 16: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/16.jpg)
CMS のフェーズ
1 InitialMarking (STW)Root からのマーキング VM_CMS_Initial_Mark::doit()
2 Marking 通常の concurrent marking CMSCollector::markFromRoots()
3 Precleaning 弱参照系の concurrent marking CMSCollector::preclean()
4 AbortablePreclean CMSCollector::abortable_preclean()
5 FinalMarking (STW)Marking の残り VM_CMS_Final_Remark::doit()
6 Sweeping 回収 CMSCollector::sweep
7 Resizing 空間のサイズ調整 CMSCollector::compute_new_size
8 Resetting ビットマップのクリアなど CMSCollector::reset
9 Idling CMSWaitDuration ミリ秒待機
16
- ConcurrentMarkSweepThread::run at concurrentMarkSweepThread.cpp:128 - CMSCollector::collect_in_background at concurrentMarkSweepGeneration.cpp:2246
3 と 4 の処理は省略されることがある。
![Page 17: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/17.jpg)
17
InitialMarking• Root からのマークは STW で行う。• ConcurrentMarkSweepThread スレッドが指示を出すが、実際の
処理は VMThread が行う。
#0 CMSBitMap::mark() at globalDefinitions.hpp:418#1 MarkRefsIntoClosure::do_oop() at concurrentMarkSweepGeneration.cpp:6586#2 MarkRefsIntoClosure::do_oop_work<oopDesc*>(oopDesc**) at hotspot/src/share/vm/utilities/globalDefinitions.hpp:418#3 MarkRefsIntoClosure::do_oop() at concurrentMarkSweepGeneration.cpp:6590#4 Universe::oops_do() at hotspot/src/share/vm/memory/universe.cpp:208#5 SharedHeap::process_strong_roots() at hotspot/src/share/vm/memory/sharedHeap.cpp:139#6 GenCollectedHeap::gen_process_strong_roots() at hotspot/src/share/vm/memory/genCollectedHeap.cpp:741#7 CMSCollector::checkpointRootsInitialWork() at concurrentMarkSweepGeneration.cpp:3570#8 CMSCollector::checkpointRootsInitial() at concurrentMarkSweepGeneration.cpp:3489#9 CMSCollector::do_CMS_operation() atconcurrentMarkSweepGeneration.cpp:6306#10 VM_CMS_Initial_Mark::doit() at concurrentMarkSweep/vmCMSOperations.cpp:140#11 VM_Operation::evaluate() at hotspot/src/share/vm/runtime/vm_operations.cpp:65
![Page 18: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/18.jpg)
18
Marking#0 CMSBitMap::mark() at globalDefinitions.hpp:418#1 PushOrMarkClosure::do_oop() at concurrentMarkSweepGeneration.cpp:7555#2 PushOrMarkClosure::do_oop_work<oopDesc*>(oopDesc**) at globalDefinitions.hpp:418#3 PushOrMarkClosure::do_oop_nv(oopDesc**) () at hotspot/src/share/vm/runtime/thread.hpp:1826#4 instanceKlass::oop_oop_iterate_nv() at hotspot/src/share/vm/oops/instanceKlass.cpp:1825#5 instanceRefKlass::oop_oop_iterate_nv() at hotspot/src/share/vm/oops/instanceRefKlass.cpp:285#6 oopDesc::oop_iterate() at /globalDefinitions.hpp:418#7 MarkFromRootsClosure::scanOopsInOop() at concurrentMarkSweepGeneration.cpp:7215#8 MarkFromRootsClosure::do_bit() at concurrentMarkSweepGeneration.cpp:7113#9 BitMap::iterate() at hotspot/src/share/vm/utilities/bitMap.cpp:512#10 BitMap::iterate() at globalDefinitions.hpp:418#11 CMSBitMap::iterate() at globalDefinitions.hpp:418#12 CMSCollector::do_marking_st() at concurrentMarkSweepGeneration.cpp:4325#13 CMSCollector::markFromRootsWork() at concurrentMarkSweepGeneration.cpp:3692#14 CMSCollector::markFromRoots() at concurrentMarkSweepGeneration.cpp:3629#15 CMSCollector::collect_in_background() at concurrentMarkSweepGeneration.cpp:2288#16 ConcurrentMarkSweepThread::run() at concurrentMarkSweepThread.cpp:128
![Page 19: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/19.jpg)
19
Preclean
#0 CMSDrainMarkingStackClosure::do_void() at concurrentMarkSweepGeneration.cpp:8638#1 ReferenceProcessor::preclean_discovered_reflist() at hotspot/src/share/vm/memory/referenceProcessor.cpp:1433#2 ReferenceProcessor::preclean_discovered_references() at hotspot/src/share/vm/memory/referenceProcessor.cpp:1345#3 CMSCollector::preclean_work() at concurrentMarkSweepGeneration.cpp:4542#4 CMSCollector::preclean() at concurrentMarkSweepGeneration.cpp:4376#5 CMSCollector::collect_in_background() at concurrentMarkSweepGeneration.cpp:2300#6 ConcurrentMarkSweepThread::run() at concurrentMarkSweepThread.cpp:128
![Page 20: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/20.jpg)
20
FinalMarking• Marking の最後は STW して行う。• Card marking によって dirty card がある場所のみをマークする。
#0 CMSBitMap::mark_range() at hotspot/src/share/vm/memory/cardTableRS.hpp:150#1 CardTableModRefBS::dirty_card_iterate() at hotspot/src/share/vm/memory/cardTableModRefBS.cpp:617#2 CMSParRemarkTask::do_dirty_card_rescan_tasks() at concurrentMarkSweepGeneration.cpp:5322#3 CMSParRemarkTask::work() at concurrentMarkSweepGeneration.cpp:5171#4 GangWorker::loop() at hotspot/src/share/vm/utilities/workgroup.cpp:308#5 GangWorker::run() at OpenJDK/hotspot/src/share/vm/utilities/workgroup.cpp:224#6 java_start() at OpenJDK/hotspot/src/os/linux/vm/os_linux.cpp:852
![Page 21: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/21.jpg)
21
Sweep(1/3)• CMSCollector::sweep at concurrentMarkSweepGeneration.cpp:5976
void CMSCollector::sweep(bool asynch) {
// PermGen の sweep が禁止されていた場合でも無効なオブジェクトを // _perm_gen_verify_bit_map BitMap に移す。 MarkDeadObjectsClosure mdo(this, _permGen->cmsSpace(), markBitMap(), perm_gen_verify_bit_map());
_permGen->cmsSpace()->blk_iterate(&mdo);
// Sweep 処理 sweepWork(_permGen, asynch);
![Page 22: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/22.jpg)
22
Sweep(2/3)
concurrentMarkSweepGeneration.cpp:9214
size_t MarkDeadObjectsClosure::do_blk(HeapWord* addr) { size_t res = _sp->block_size_no_stall(addr, _collector); if (_sp->block_is_obj(addr)) { if (_live_bit_map->isMarked(addr)) { } else { _dead_bit_map->mark(addr); // mark the dead object } } return res;}
#0 MarkDeadObjectsClosure::do_blk() at concurrentMarkSweepGeneration.cpp:9214#1 CompactibleFreeListSpace::blk_iterate() at concurrentMarkSweep/compactibleFreeListSpace.cpp:771#2 CMSCollector::sweep() at concurrentMarkSweepGeneration.cpp:6000#3 CMSCollector::collect_in_background() at concurrentMarkSweepGeneration.cpp:2333#4 ConcurrentMarkSweepThread::run() at concurrentMarkSweepThread.cpp:128
![Page 23: Concurrent Mark&Sweep 第 6 回 JVM ソースコードリーディングの会 (OpenJDK)](https://reader035.vdocuments.net/reader035/viewer/2022062218/56816715550346895ddb8378/html5/thumbnails/23.jpg)
23
Sweep(3/)
#0 SweepClosure::do_yield_work() at concurrentMarkSweepGeneration.cpp:8435#1 SweepClosure::do_yield_check(HeapWord*) at hotspot/src/share/vm/utilities/globalDefinitions.hpp:418#2 SweepClosure::do_blk_careful() at concurrentMarkSweepGeneration.cpp:8017#3 CompactibleFreeListSpace::blk_iterate_careful() at concurrentMarkSweep/compactibleFreeListSpace.cpp:763#4 CMSCollector::sweepWork() at concurrentMarkSweepGeneration.cpp:6201#5 CMSCollector::sweep() at concurrentMarkSweepGeneration.cpp:6018#6 CMSCollector::collect_in_background() at concurrentMarkSweepGeneration.cpp:2333#7 ConcurrentMarkSweepThread::run() at concurrentMarkSweepThread.cpp:128