对象分配策略(3个阶段)
TLAB(Thread Local Allocation Buffer)线程本地分配缓冲区
Eden区中分配
Humongous区分配
G1算法将堆划分为若干个区域(Region),它仍然属于分代收集器。
不过,这些区域的一部分包含新生代,新生代的垃圾收集依然采用暂停所有应用线程的方式,将存活对象拷贝到老年代或者Survivor空间。
老年代也分成很多区域,G1收集器通过将对象从一个区域复制到另外一个区域,完成了清理工作。
在G1中,还有一种特殊的区域,叫Humongous区域。 如果一个对象占用的空间超过了分区容量50%以上,G1收集器就认为这是一个巨型对象。
这些巨型对象,默认直接会被分配在年老代,G1划分了一个Humongous区,它用来专门存放巨型对象。
如果一个H区装不下一个巨型对象,那么G1会寻找连续的H分区来存储。为了能找到连续的H区,有时候不得不启动Full GC
G1两种GC模式
Young GC和Mixed GC,两种都是Stop The World(STW)
Young GC:选定所有年轻代里的Region, 主要是对Eden区进行GC,它在Eden空间耗尽时会被触发
Mixed GC:选定所有年轻代里的Region,外加根据global concurrent marking统计得出收集收益高的若干老年代Region,不仅进行正常的新生代垃圾收集,同时也回收部分后台扫描线程标记的老年代分区
Young GC 阶段:
阶段1:根扫描 静态和本地对象被扫描
阶段2:更新RS 处理dirty card队列更新RS
阶段3:处理RS 检测从年轻代指向年老代的对象
阶段4:对象拷贝 拷贝存活的对象到survivor/old区域
阶段5:处理引用队列 软引用,弱引用,虚引用处理
RSet(Remembered Set): 全称是Remembered Set,作用是跟踪指向某个heap区内的对象引用, RSet其实是一个Hash
Table,Key是别的Region的起始地址,Value是一个集合,里面的元素是Card Table的Index. 典型的空间换时间工具.
卡表(Card Table):一个Card Table将一个分区在逻辑上划分为固定大小的连续区域,每个区域称之为卡。卡通常较小,
介于128到512字节之间。Card Table通常为字节数组,由Card的索引(即数组下标)来标识每个分区的空间地址
Code Root: code root指的是经过JIT编译后的代码里,引用了heap中的对象。引用关系保存在RSet中。
Mixed GC
步骤1:全局并发标记(global concurrent marking)
步骤2:拷贝存活对象(evacuation)
global concurrent marking:
初始标记(initial mark,STW):在此阶段,G1 GC 对根进行标记。该阶段与常规的 (STW) 年轻代垃圾回收密切相关。
根区域扫描(root region scan):G1 GC 在初始标记的存活区扫描对老年代的引用,并标记被引用的对象。该阶段与应用程序(非 STW)同时运行,并且只有完成该阶段后,才能开始下一次 STW 年轻代垃圾回收。
并发标记(Concurrent Marking):G1 GC 在整个堆中查找可访问的(存活的)对象。该阶段与应用程序同时运行,可以被 STW 年轻代垃圾回收中断
最终标记(Remark,STW):该阶段是 STW 回收,帮助完成标记周期。G1 GC 清空 SATB 缓冲区,跟踪未被访问的存活对象,并执行引用处理。
清除垃圾(Cleanup,STW):在这个最后阶段,G1 GC 执行统计和 RSet 净化的 STW 操作。在统计期间,G1 GC 会识别完全空闲的区域和可供进行混合垃圾回收的区域。清理阶段在将空白区域重置并返回到空闲列表时为部分并发。
evacuation:
采用的复制的清理策略,当GC完成后,会重新释放空间
SATB
全称是Snapshot-At-The-Beginning,由字面理解,是GC开始时活着的对象的一个快照。它是通过Root Tracing
得到的,作用是维持并发GC的正确性。SATB也是有副作用的,如果被替换的白对象就是要被收集的垃圾,这次的标记会让它躲
过GC,这就是float garbage。因为SATB的做法精度比较低,所以造成的float garbage也会比较多
mixed gc 控制参数
G1HeapWastePercent:在global concurrent marking结束之后,我们可以知道old gen regions中有多少空间要
被回收,在每次YGC之后和再次发生Mixed GC之前,会检查垃圾占比是否达到此参数,只有达到了,下次才会发生Mixed GC。
G1MixedGCLiveThresholdPercent:old generation region中的存活对象的占比,只有在此参数之下,才会被选
入CSet。
G1MixedGCCountTarget:一次global concurrent marking之后,最多执行Mixed GC的次数。
G1OldCSetRegionThresholdPercent:一次Mixed GC中能被选入CSet的最多old generation region数量。
-XX:MaxGCPauseMillis=200
Pause Prediction Model: 指定一个G1收集过程目标停顿时间,默认值200ms,不过它不是硬性条件,只是期望值。G1根据这个模型统计计算出来的历史数据来预测本次收集需要选择的Region数量,从而尽量满足用户设定的目标停顿时间。
Young GC:选定所有新生代里的region。通过控制新生代的region个数来控制young GC的开销。
Mixed GC:选定所有新生代里的region,外加根据global concurrent marking统计得出收集收益高的若干老年代region。在用户指定的开销目标范围内尽可能选择收益高的老年代region。
CSet(collection set):在一次垃圾收集器中被收集的区域集合。
-XX:G1HeapRegionSize=32m
设置的 G1 区域的大小。值是 2 的幂,范围是1MB到32MB之间。默认是根据最小的Java堆(Xms)大小划分出约2048个区域(即Xms/2048)。
-XX:ParallelGCThreads=n
设置 STW 工作线程数的值。将n的值设置为逻辑处理器的数量。n的值与逻辑处理器的数量相同,最多为8。
-XX:ConcGCThreads=n
设置并行标记的线程数。将 n 设置为并行垃圾回收线程数 (ParallelGCThreads) 的 1/4 左右.
-XX:InitiatingHeapOccupancyPercent=45
设置触发标记周期的Java堆占用率阈值。默认占用率是整个Java堆的45%
-XX:G1ReservePercent=10
设置作为空闲空间的预留内存百分比,以降低目标空间溢出的风险。默认值是 10%。
-XX:PretenureSizeThreshold=<value>
Byte,作用是当新对象申请的内存空间大于这个参数值的时候,直接扔到old区
-XX:TargetSurvivorRatio=90 提高 from 区的利用率,使 from 区使用到 90%时,再将对象送入年老代
-XX:MaxTenuringThreshold=15 来设置当对象年龄达到阈值时,就移入年老代,成为老年对象, 默认值是 15
避免使用以下参数:
避免使用 -Xmn 选项或 -XX:NewRatio 等其他相关选项显式设置年轻代大小。固定年轻代的大小会覆盖暂停时间目标
Young GC:GC pause (G1 Evacuation Pause)
Young GC:GC pause (G1 Humongous Allocation)
Mixed GC:GC pause (G1 Evacuation Pause)
Full GC:Full GC(Allocation Failure)
The G1 collector runs parts of its collection while the application continues to run and
there is a risk that the application will allocate objects faster than the garbage collector can recover free space
In G1, the failure (exhaustion of the Java heap) occurs while G1 is copying live data out of one region (evacuating)
into another region. The copying is done to compact the live data. If a free (empty) region cannot be found during the
evacuation of a region being garbage collected, then an allocation failure occurs (because there is no space to allocate
the live objects from the region being evacuated) and a stop-the-world (STW) full collection is done.
Full GC
在某些情况下(mixed GC实在无法跟上程序分配内存的速度,导致老年代填满无法继续进行Mixed GC),G1触发了Full GC,这时G1会退化使用Serial收集器(full GC)来完成垃圾的清理工作,它仅仅使用单线程来完成GC工作,GC暂停时间将达到秒级别的。整个应用处于假死状态,不能处理任何请求(Full GC会gc heap和metadata)
Full GC原因
并发模式失败: G1启动标记周期,但在Mix GC之前,老年代就被填满,这时候G1会放弃标记周期。
gc log: Allocation (Evacuation) Failure
方案:增加堆大小,或者调整周期(例如增加线程数-XX:ConcGCThreads等)。
晋升失败或者疏散失败:G1在进行GC的时候没有足够的内存供存活对象或晋升对象使用
gc log:to-space exhausted, to-space overflow
方案:
a,增加 -XX:G1ReservePercent 选项的值(并相应增加总的堆大小),为“目标空间”增加预留内存量。
b,通过减少 -XX:InitiatingHeapOccupancyPercent 提前启动标记周期。
c,也可以通过增加 -XX:ConcGCThreads 选项的值来增加并行标记线程的数目。
巨型对象分配失败: 当巨型对象找不到合适的空间进行分配时
gc log: G1 Humongous Allocation, Allocation Failure
方案:避免分配大量的巨型对象,增加内存或者增大-XX:G1HeapRegionSize,使巨型对象不再是巨型对象。
执行特定调用
System.gc()
jmap -histo:live <pid>
jmap -dump
jcmd xxxxxx.xxxx GC.run
附录G1 GC其他参数
-XX:+G1UseAdaptiveConcRefinement
-XX:G1ConcRefinementGreenZone=<ergo>
-XX:G1ConcRefinementYellowZone=<ergo>
-XX:G1ConcRefinementRedZone=<ergo>
-XX:G1ConcRefinementThreads=<ergo>
(<ergo> means that the actual value is determined ergonomically depending on the environment.)
-XX:+ReduceInitialCardMarks
-XX:-ParallelRefProcEnabled
-XX:G1RSetUpdatingPauseTimePercent=10
-XX:G1SummarizeRSetStatsPeriod=0
-XX:GCTimeRatio=12
-XX:+UseLargePages
-XX:LargePageSizeInBytes=10m
附录GC Cause
_java_lang_system_gc: "System.gc()";
_full_gc_alot: "FullGCAlot";
_scavenge_alot: "ScavengeAlot";
_allocation_profiler: "Allocation Profiler";
_jvmti_force_gc: "JvmtiEnv ForceGarbageCollection";
_gc_locker: "GCLocker Initiated GC";
_heap_inspection: "Heap Inspection Initiated GC";
_heap_dump: "Heap Dump Initiated GC";
_wb_young_gc: "WhiteBox Initiated Young GC";
_update_allocation_context_stats_inc: "Update Allocation Context Stats";
_update_allocation_context_stats_full: "Update Allocation Context Stats";
_no_gc: "No GC";
_allocation_failure: "Allocation Failure";
_tenured_generation_full: "Tenured Generation Full";
_metadata_GC_threshold: "Metadata GC Threshold";
_cms_generation_full: "CMS Generation Full";
_cms_initial_mark: "CMS Initial Mark";
_cms_final_remark: "CMS Final Remark";
_cms_concurrent_mark: "CMS Concurrent Mark";
_old_generation_expanded_on_last_scavenge: "Old Generation Expanded On Last Scavenge";
_old_generation_too_full_to_scavenge: "Old Generation Too Full To Scavenge";
_adaptive_size_policy: "Ergonomics";
_g1_inc_collection_pause: "G1 Evacuation Pause";
_g1_humongous_allocation: "G1 Humongous Allocation";
_last_ditch_collection: "Last ditch collection";
_last_gc_cause: "ILLEGAL VALUE - last gc cause - ILLEGAL VALUE";
default: "unknown GCCause";