序
本文主要試用一下JDK12新引入的ShenandoahGC
ShenandoahGC
Shenandoah是一款concurrent及parallel的垃圾收集器
- 跟ZGC一樣也是面向low-pause-time的垃圾收集器,不過(guò)ZGC是基于colored pointers來(lái)實(shí)現(xiàn),而Shenandoah GC是基于brooks pointers來(lái)實(shí)現(xiàn)
- 與G1 GC相比,G1的evacuation是parallel的但不是concurrent宪拥,而Shenandoah的evacuation是concurrent晓淀,因而能更好地減少pause time
- 與G1 GC一樣,ShenandoahGC也是基于region的GC,不同的是ShenandoahGC在邏輯上沒(méi)有分代锡垄,因而就沒(méi)有young/old
GC cycle
ShenandoahGC主要有如下幾個(gè)階段:
Snapshot-at-the-beginning concurrent mark
這里包含Init Mark(
Pause
)、Concurrent Mark祭隔、Final Mark(Pause
)货岭;這里使用到了White(not yet visited
)、Gray(visited, but references are not scanned yet
)疾渴、Black(visited, and fully scanned
) Color算法進(jìn)行mark
Concurrent evacuation
這個(gè)就是與G1不同的evacuation階段千贯,它是concurrent的;這里用到了Brooks Pointers(
object version change with additional atomically changed indirection
)算法進(jìn)行copy搞坝,
Concurrent update references (optional)
這里包含Init update Refs(
Pause
)搔谴、Concurrent update Refs、Final update Refs(Pause
)
Final Mark或者Final update Refs之后都可能進(jìn)行Concurrent cleanup桩撮,進(jìn)行垃圾回收敦第,reclaims region
相關(guān)參數(shù)
Shenandoah開(kāi)頭的參數(shù)
bool ShenandoahAcmpBarrier = true {diagnostic} {default}
bool ShenandoahAllocFailureALot = false {diagnostic} {default}
uintx ShenandoahAllocSpikeFactor = 5 {experimental} {default}
intx ShenandoahAllocationStallThreshold = 10000 {diagnostic} {default}
uintx ShenandoahAllocationThreshold = 0 {experimental} {default}
bool ShenandoahAllocationTrace = false {diagnostic} {default}
bool ShenandoahAllowMixedAllocs = true {diagnostic} {default}
bool ShenandoahAlwaysClearSoftRefs = false {experimental} {default}
bool ShenandoahAlwaysPreTouch = false {diagnostic} {default}
bool ShenandoahCASBarrier = true {diagnostic} {default}
bool ShenandoahCloneBarrier = true {diagnostic} {default}
uintx ShenandoahCodeRootsStyle = 2 {experimental} {default}
bool ShenandoahCommonGCStateLoads = false {experimental} {default}
bool ShenandoahConcurrentScanCodeRoots = true {experimental} {default}
uintx ShenandoahControlIntervalAdjustPeriod = 1000 {experimental} {default}
uintx ShenandoahControlIntervalMax = 10 {experimental} {default}
uintx ShenandoahControlIntervalMin = 1 {experimental} {default}
uintx ShenandoahCriticalFreeThreshold = 1 {experimental} {default}
bool ShenandoahDecreaseRegisterPressure = false {diagnostic} {default}
bool ShenandoahDegeneratedGC = true {diagnostic} {default}
bool ShenandoahDontIncreaseWBFreq = true {experimental} {default}
bool ShenandoahElasticTLAB = true {diagnostic} {default}
uintx ShenandoahEvacAssist = 10 {experimental} {default}
uintx ShenandoahEvacReserve = 5 {experimental} {default}
bool ShenandoahEvacReserveOverflow = true {experimental} {default}
double ShenandoahEvacWaste = 1.200000 {experimental} {default}
uintx ShenandoahFreeThreshold = 10 {experimental} {default}
uintx ShenandoahFullGCThreshold = 3 {experimental} {default}
ccstr ShenandoahGCHeuristics = adaptive {experimental} {default}
uintx ShenandoahGarbageThreshold = 60 {experimental} {default}
uintx ShenandoahGuaranteedGCInterval = 300000 {experimental} {default}
size_t ShenandoahHeapRegionSize = 0 {experimental} {default}
bool ShenandoahHumongousMoves = true {experimental} {default}
intx ShenandoahHumongousThreshold = 100 {experimental} {default}
uintx ShenandoahImmediateThreshold = 90 {experimental} {default}
bool ShenandoahImplicitGCInvokesConcurrent = true {experimental} {default}
uintx ShenandoahInitFreeThreshold = 70 {experimental} {default}
bool ShenandoahKeepAliveBarrier = true {diagnostic} {default}
uintx ShenandoahLearningSteps = 5 {experimental} {default}
bool ShenandoahLoopOptsAfterExpansion = true {experimental} {default}
uintx ShenandoahMarkLoopStride = 1000 {experimental} {default}
intx ShenandoahMarkScanPrefetch = 32 {experimental} {default}
size_t ShenandoahMaxRegionSize = 33554432 {experimental} {default}
uintx ShenandoahMergeUpdateRefsMaxGap = 200 {experimental} {default}
uintx ShenandoahMergeUpdateRefsMinGap = 100 {experimental} {default}
uintx ShenandoahMinFreeThreshold = 10 {experimental} {default}
size_t ShenandoahMinRegionSize = 262144 {experimental} {default}
bool ShenandoahOOMDuringEvacALot = false {diagnostic} {default}
bool ShenandoahOptimizeInstanceFinals = false {experimental} {default}
bool ShenandoahOptimizeStableFinals = false {experimental} {default}
bool ShenandoahOptimizeStaticFinals = true {experimental} {default}
bool ShenandoahPacing = true {experimental} {default}
uintx ShenandoahPacingCycleSlack = 10 {experimental} {default}
uintx ShenandoahPacingIdleSlack = 2 {experimental} {default}
uintx ShenandoahPacingMaxDelay = 10 {experimental} {default}
double ShenandoahPacingSurcharge = 1.100000 {experimental} {default}
uintx ShenandoahParallelRegionStride = 1024 {experimental} {default}
uint ShenandoahParallelSafepointThreads = 4 {experimental} {default}
bool ShenandoahPreclean = true {experimental} {default}
bool ShenandoahReadBarrier = true {diagnostic} {default}
uintx ShenandoahRefProcFrequency = 5 {experimental} {default}
bool ShenandoahRegionSampling = true {experimental} {command line}
int ShenandoahRegionSamplingRate = 40 {experimental} {default}
bool ShenandoahSATBBarrier = true {diagnostic} {default}
uintx ShenandoahSATBBufferFlushInterval = 100 {experimental} {default}
size_t ShenandoahSATBBufferSize = 1024 {experimental} {default}
bool ShenandoahStoreCheck = false {diagnostic} {default}
bool ShenandoahStoreValEnqueueBarrier = false {diagnostic} {default}
bool ShenandoahStoreValReadBarrier = true {diagnostic} {default}
bool ShenandoahSuspendibleWorkers = false {experimental} {default}
size_t ShenandoahTargetNumRegions = 2048 {experimental} {default}
bool ShenandoahTerminationTrace = false {diagnostic} {default}
bool ShenandoahUncommit = true {experimental} {default}
uintx ShenandoahUncommitDelay = 300000 {experimental} {default}
uintx ShenandoahUnloadClassesFrequency = 0 {experimental} {default}
ccstr ShenandoahUpdateRefsEarly = adaptive {experimental} {default}
bool ShenandoahVerify = false {diagnostic} {default}
intx ShenandoahVerifyLevel = 4 {diagnostic} {default}
bool ShenandoahWriteBarrier = true {diagnostic} {default}
其中有一些是diagnostic用的,比如ShenandoahAcmpBarrier店量、ShenandoahAllocFailureALot芜果、ShenandoahAllocationStallThreshold等
Heuristics相關(guān)參數(shù)
ccstr ShenandoahGCHeuristics = adaptive {experimental} {default}
uintx ShenandoahInitFreeThreshold = 70 {experimental} {default}
uintx ShenandoahMinFreeThreshold = 10 {experimental} {default}
uintx ShenandoahAllocSpikeFactor = 5 {experimental} {default}
uintx ShenandoahGarbageThreshold = 60 {experimental} {default}
uintx ShenandoahFreeThreshold = 10 {experimental} {default}
uintx ShenandoahAllocationThreshold = 0 {experimental} {default}
ccstr ShenandoahUpdateRefsEarly = adaptive {experimental} {default}
Heuristics主要用于告訴Shenandoah何時(shí)啟動(dòng)一個(gè)GC cycle,其中ShenandoahGCHeuristics用于選擇不同的策略融师,其可選值有adaptive(
默認(rèn)
)右钾、static、compact旱爆、passive(diagnostic用
)舀射、aggressive(diagnostic用
)
- adaptive方式主要通過(guò)ShenandoahInitFreeThreshold(
Initial remaining free heap threshold for learning steps
)、ShenandoahMinFreeThreshold(free space threshold at which heuristics triggers the GC unconditionally
)怀伦、ShenandoahAllocSpikeFactor(How much heap to reserve for absorbing allocation spikes
)脆烟、XX:ShenandoahGarbageThreshold(Sets the percentage of garbage a region need to contain before it can be marked for collection
)來(lái)設(shè)置合適啟動(dòng)GC cycle - static方式主要是基于heap occupancy以及allocation pressure來(lái)決定是否啟動(dòng)GC cycle,相關(guān)參數(shù)有:ShenandoahFreeThreshold(
Set the percentage of free heap at which a GC cycle is started
)房待、ShenandoahAllocationThreshold(Set percentage of memory allocated since last GC cycle before a new GC cycle is started
)邢羔、ShenandoahGarbageThreshold - compact方式是continuous方式的,只要有allocation發(fā)生吴攒,上一個(gè)GC cycle結(jié)束之后就啟動(dòng)新的GC cycle张抄,相關(guān)參數(shù)有ConcGCThreads(
Trim down the number of concurrent GC threads to make more room for application to run
)、ShenandoahAllocationThreshold - passive方式是完全passive洼怔,當(dāng)內(nèi)存耗盡時(shí)觸發(fā)STW署惯,通常用于diagnostic
- aggressive方式是完全active的,上一個(gè)GC cycle結(jié)束之后就啟動(dòng)新的GC cycle(
有點(diǎn)類(lèi)似compact方式
)镣隶,不過(guò)它會(huì)evacuate所有的live objects极谊,通常用于diagnostic
Failure Modes
當(dāng)allocation failure發(fā)生的時(shí)候诡右,Shenandoah有一些優(yōu)雅的degradation ladder用于處理這種情況,如下:
- Pacing(
<10 ms
)
ShenandoahPacing參數(shù)默認(rèn)開(kāi)啟轻猖,Pacer用于在gc不夠快的時(shí)候去stall正在分配對(duì)象的線程帆吻,當(dāng)gc速度跟上來(lái)了就解除對(duì)這些線程的stall;stall不是無(wú)期限的咙边,有個(gè)ShenandoahPacingMaxDelay(
單位毫秒
)參數(shù)可以設(shè)置猜煮,一旦超過(guò)該值allocation就會(huì)產(chǎn)生。當(dāng)allocation壓力大的時(shí)候败许,Pacer就無(wú)能為力了王带,這個(gè)時(shí)候就會(huì)進(jìn)入下一個(gè)step
- Degenerated GC(
<100 ms
)
ShenandoahDegeneratedGC參數(shù)默認(rèn)開(kāi)啟,在這個(gè)Degenerated cycle市殷,Shenandoah使用的線程數(shù)取之于ParallelGCThreads而非ConcCGThreads
- Full GC(
>100 ms
)
當(dāng)Degenerated GC之后還沒(méi)有足夠的內(nèi)存愕撰,則進(jìn)入Full GC cycle,它會(huì)盡可能地進(jìn)行compact然后釋放內(nèi)存以確保不發(fā)生OOM
實(shí)例
啟動(dòng)參數(shù)
-server -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UsePerfData -XX:+ShenandoahRegionSampling -XX:ParallelGCThreads=4 -XX:ConcGCThreads=4 -XX:+UnlockDiagnosticVMOptions -Xlog:age*,ergo*,gc*=info
gc日志
[2019-03-21T15:12:53.771-0800][8707][gc] Consider -XX:+ClassUnloadingWithConcurrentMark if large pause times are observed on class-unloading sensitive workloads
[2019-03-21T15:12:53.862-0800][8707][gc,init] Regions: 2048 x 1024K
[2019-03-21T15:12:53.862-0800][8707][gc,init] Humongous object threshold: 1024K
[2019-03-21T15:12:53.863-0800][8707][gc,init] Max TLAB size: 1024K
[2019-03-21T15:12:53.863-0800][8707][gc,init] GC threads: 4 parallel, 4 concurrent
[2019-03-21T15:12:53.863-0800][8707][gc,init] Reference processing: parallel
[2019-03-21T15:12:53.864-0800][8707][gc ] Heuristics ergonomically sets -XX:+ExplicitGCInvokesConcurrent
[2019-03-21T15:12:53.864-0800][8707][gc ] Heuristics ergonomically sets -XX:+ShenandoahImplicitGCInvokesConcurrent
[2019-03-21T15:12:53.864-0800][8707][gc,init] Shenandoah heuristics: adaptive
[2019-03-21T15:12:53.864-0800][8707][gc,heap] Initialize Shenandoah heap with initial size 128M
[2019-03-21T15:12:53.865-0800][8707][gc,ergo] Pacer for Idle. Initial: 40M, Alloc Tax Rate: 1.0x
[2019-03-21T15:12:53.883-0800][8707][gc,init] Safepointing mechanism: global-page poll
[2019-03-21T15:12:53.883-0800][8707][gc ] Using Shenandoah
[2019-03-21T15:12:53.884-0800][8707][gc,heap,coops] Heap address: 0x0000000780000000, size: 2048 MB, Compressed Oops mode: Zero based, Oop shift amount: 3
[2019-03-21T15:12:59.530-0800][14083][gc ] Trigger: Metadata GC Threshold
[2019-03-21T15:12:59.532-0800][14083][gc,ergo ] Free: 1813M (1813 regions), Max regular: 1024K, Max humongous: 1855488K, External frag: 1%, Internal frag: 0%
[2019-03-21T15:12:59.532-0800][14083][gc,ergo ] Evacuation Reserve: 103M (103 regions), Max regular: 1024K
[2019-03-21T15:12:59.532-0800][14083][gc,start ] GC(0) Concurrent reset
[2019-03-21T15:12:59.533-0800][14083][gc,task ] GC(0) Using 4 of 4 workers for concurrent reset
[2019-03-21T15:12:59.533-0800][14083][gc ] GC(0) Concurrent reset 132M->132M(2048M) 0.441ms
[2019-03-21T15:12:59.533-0800][15619][gc,start ] GC(0) Pause Init Mark (process weakrefs) (unload classes)
[2019-03-21T15:12:59.533-0800][15619][gc,task ] GC(0) Using 4 of 4 workers for init marking
[2019-03-21T15:12:59.541-0800][15619][gc,ergo ] GC(0) Pacer for Mark. Expected Live: 204M, Free: 1813M, Non-Taxable: 181M, Alloc Tax Rate: 0.4x
[2019-03-21T15:12:59.541-0800][15619][gc ] GC(0) Pause Init Mark (process weakrefs) (unload classes) 7.568ms
[2019-03-21T15:12:59.541-0800][14083][gc,start ] GC(0) Concurrent marking (process weakrefs) (unload classes)
[2019-03-21T15:12:59.541-0800][14083][gc,task ] GC(0) Using 4 of 4 workers for concurrent marking
[2019-03-21T15:12:59.619-0800][14083][gc ] GC(0) Concurrent marking (process weakrefs) (unload classes) 132M->134M(2048M) 78.373ms
[2019-03-21T15:12:59.619-0800][14083][gc,start ] GC(0) Concurrent precleaning
[2019-03-21T15:12:59.619-0800][14083][gc,task ] GC(0) Using 1 of 4 workers for concurrent preclean
[2019-03-21T15:12:59.622-0800][14083][gc ] GC(0) Concurrent precleaning 134M->134M(2048M) 2.397ms
[2019-03-21T15:12:59.622-0800][15619][gc,start ] GC(0) Pause Final Mark (process weakrefs) (unload classes)
[2019-03-21T15:12:59.622-0800][15619][gc,task ] GC(0) Using 4 of 4 workers for final marking
[2019-03-21T15:12:59.625-0800][15619][gc,stringtable] GC(0) Cleaned string table, strings: 13692 processed, 50 removed
[2019-03-21T15:12:59.626-0800][15619][gc,ergo ] GC(0) Adaptive CSet Selection. Target Free: 204M, Actual Free: 1914M, Max CSet: 85M, Min Garbage: 0M
[2019-03-21T15:12:59.626-0800][15619][gc,ergo ] GC(0) Collectable Garbage: 117M (97% of total), 8M CSet, 126 CSet regions
[2019-03-21T15:12:59.626-0800][15619][gc,ergo ] GC(0) Immediate Garbage: 0M (0% of total), 0 regions
[2019-03-21T15:12:59.626-0800][15619][gc,ergo ] GC(0) Pacer for Evacuation. Used CSet: 126M, Free: 1811M, Non-Taxable: 181M, Alloc Tax Rate: 1.1x
[2019-03-21T15:12:59.626-0800][15619][gc ] GC(0) Pause Final Mark (process weakrefs) (unload classes) 4.712ms
[2019-03-21T15:12:59.626-0800][14083][gc,start ] GC(0) Concurrent cleanup
[2019-03-21T15:12:59.627-0800][14083][gc ] GC(0) Concurrent cleanup 134M->135M(2048M) 0.132ms
[2019-03-21T15:12:59.627-0800][14083][gc,ergo ] GC(0) Free: 1810M (1810 regions), Max regular: 1024K, Max humongous: 1852416K, External frag: 1%, Internal frag: 0%
[2019-03-21T15:12:59.627-0800][14083][gc,ergo ] GC(0) Evacuation Reserve: 102M (103 regions), Max regular: 1024K
[2019-03-21T15:12:59.627-0800][14083][gc,start ] GC(0) Concurrent evacuation
[2019-03-21T15:12:59.627-0800][14083][gc,task ] GC(0) Using 4 of 4 workers for concurrent evacuation
[2019-03-21T15:12:59.643-0800][14083][gc ] GC(0) Concurrent evacuation 135M->145M(2048M) 15.912ms
[2019-03-21T15:12:59.643-0800][15619][gc,start ] GC(0) Pause Init Update Refs
[2019-03-21T15:12:59.643-0800][15619][gc,ergo ] GC(0) Pacer for Update Refs. Used: 145M, Free: 1810M, Non-Taxable: 181M, Alloc Tax Rate: 1.1x
[2019-03-21T15:12:59.643-0800][15619][gc ] GC(0) Pause Init Update Refs 0.090ms
[2019-03-21T15:12:59.643-0800][14083][gc,start ] GC(0) Concurrent update references
[2019-03-21T15:12:59.643-0800][14083][gc,task ] GC(0) Using 4 of 4 workers for concurrent reference update
[2019-03-21T15:12:59.652-0800][14083][gc ] GC(0) Concurrent update references 145M->147M(2048M) 9.028ms
[2019-03-21T15:12:59.652-0800][15619][gc,start ] GC(0) Pause Final Update Refs
[2019-03-21T15:12:59.652-0800][15619][gc,task ] GC(0) Using 4 of 4 workers for final reference update
[2019-03-21T15:12:59.653-0800][15619][gc ] GC(0) Pause Final Update Refs 0.489ms
[2019-03-21T15:12:59.653-0800][14083][gc,start ] GC(0) Concurrent cleanup
[2019-03-21T15:12:59.653-0800][14083][gc ] GC(0) Concurrent cleanup 147M->21M(2048M) 0.088ms
[2019-03-21T15:12:59.653-0800][14083][gc,ergo ] Free: 1924M (1924 regions), Max regular: 1024K, Max humongous: 1840128K, External frag: 7%, Internal frag: 0%
[2019-03-21T15:12:59.653-0800][14083][gc,ergo ] Evacuation Reserve: 103M (103 regions), Max regular: 1024K
[2019-03-21T15:12:59.653-0800][14083][gc,ergo ] Pacer for Idle. Initial: 40M, Alloc Tax Rate: 1.0x
[2019-03-21T15:17:59.666-0800][14083][gc ] Trigger: Time since last GC (300009 ms) is larger than guaranteed interval (300000 ms)
gc visualizer
有個(gè)shenandoah-visualizer工具可以用來(lái)可視化ShenandoahGC醋寝,可視化效果如下:
小結(jié)
- Shenandoah是一款concurrent及parallel的垃圾收集器搞挣;跟ZGC一樣也是面向low-pause-time的垃圾收集器,不過(guò)ZGC是基于colored pointers來(lái)實(shí)現(xiàn)音羞,而Shenandoah GC是基于brooks pointers來(lái)實(shí)現(xiàn)囱桨;與G1 GC相比,G1的evacuation是parallel的但不是concurrent黄选,而Shenandoah的evacuation是concurrent蝇摸,因而能更好地減少pause time;與G1 GC一樣办陷,ShenandoahGC也是基于region的GC,不同的是ShenandoahGC在邏輯上沒(méi)有分代律歼,因而就沒(méi)有young/old
- Shenandoah的GC cycle主要有Snapshot-at-the-beginning concurrent mark
包括Init Mark(
Pause)民镜、Concurrent Mark、Final Mark(
Pause)
险毁、Concurrent evacuation制圈、Concurrent update references (optional)包括Init update Refs(
Pause)、Concurrent update Refs畔况、Final update Refs(
Pause)
鲸鹦;其中Final Mark或者Final update Refs之后都可能進(jìn)行Concurrent cleanup,進(jìn)行垃圾回收跷跪,reclaims region - Heuristics主要用于告訴Shenandoah何時(shí)啟動(dòng)一個(gè)GC馋嗜,其中ShenandoahGCHeuristics用于選擇不同的策略,其可選值有adaptive(
默認(rèn)
)吵瞻、static葛菇、compact甘磨、passive(diagnostic用
)、aggressive(diagnostic用
)眯停;另外當(dāng)allocation failure發(fā)生的時(shí)候济舆,Shenandoah有一些優(yōu)雅的degradation ladder用于處理這種情況,包括Pacing(<10 ms
)莺债、Degenerated GC(<100 ms
)滋觉、Full GC(>100 ms
)