G1
<ol><li>将Java堆拆分成多个大小相等的Region, JVM最多可以用2048个Region, Region的大小必须是2的倍数, 比如4G 4096/2048=2M(每个Region),可以手动设置 "-XX: G1HeapRegionSize"</li></ol>
<span style="font-size: inherit;"><font color="#ff0000">2.最大的特点是让我们设置一个垃圾回收预期停顿时间</font></span><br>
比如追踪发现, 1个Region中的垃圾对象有10MB, 回收耗时1s,另一个Region有20MB,回收耗时200ms
G1也有新生代和老年代的概念, 只不过是逻辑上的概念
新生代也有Eden和Survivor的概念吗?
之前有一个新生代的参数 "-XX:SurvivorRatio=8", 所以这里还是区分新生代的Region那些是属于Eden和Survivor, <br>比如新生代有100个Region, 那么可能有80个Region是Eden, 2个Survivor各自占10个Region
简单总结:
G1可以做到让你来设定垃圾回收对系统的影响, 他通过内存拆分成大量小Region, 一级追踪每个Region可以回收对象大小和预估时间,最后在垃圾回收的时候, 尽量把垃圾回收堆系统的影响控制在你指定的范围内, 同时在有限的时间内回收尽可能多的对象
<ul><li><font color="#4669ea"><b>回收触发时机-新生代</b></font></li></ul>
新生代
刚开始新生代对堆内存占比是5%, 比如4G, 那么新生代就是200MB,对应100个Region, 可以通过"-XX:G1NewSizePercent"设置比例, 随着系统运行, jvm会不停给新生代增加Region, 但不会超过60%, 可以通过"-XX:G1MaxNewSizePercent"
一旦新生代达到了设定的占据堆内存大小60%, 比如1200个Region, Eden可能占据了1000个Region, 每个survivor是100个Region,而Eden还占满了对象, 这个时候还是会触发新生代的GC, G1就会用之前说过的复制算法进行垃圾回收, 进入STW状态,
也不一定非要到60%才会触发这个新生代gc, <br>可能回收100个Region耗时达到设置的停顿时间也有可能触发新生代gc
老年代
什么时候触发新生代和老年代的混合回收(老年代的回收方式:混合回收)
G1 有个参数"-XX:InitiatingHeapOccupancyPercent"的默认值是45%, 意思是如果老年代占据堆内存的45%Region时候, 此时就会尝试出发新生代和老年代的混合回收阶段; 比如堆内存有2048个Region,老年代占据其中45%(接近1000个) 就会出发一个混合回收<br><br>大对象也是在这个阶段回收
垃圾回收过程
<font color="#4669ea">初始标记</font>: 仅仅是标记一些Gc Roots直接引用对象,速度很快会<b>STW</b>
<font color="#4669ea">并发标记</font>: 这个阶段允许系统的运行, 同时Gc Roots跟踪,从Gc roots开始追踪所有存活对象,这个还是很耗时, 因为要追踪全部的存活对象, 但是这个阶段是并发进行的,所以对系统活动影响不大
<font color="#4669ea">最终标记</font>: 根据并发标记阶段记录的那些对象修改, 最终标记一下有那些存活对象, 有那些是垃圾对象, 会<b>STW</b>
<font color="#4669ea">混合回收</font>: 这个阶段会计算老年代每个Region中存活对象, 存活对象的占比,还有预期回收性能和效率,接着停顿系统程序, <br>然后全力衣服尽快垃圾回收,控制好停顿时间在指定范围内
比如老年代此时1000个Region都满了,但根据设定的目标,本次垃圾回收可能只能停顿200ms,<br>那么通过之前的计算得到,可能回收800个Region刚好需要200ms, 那么只能回收800个Region, <br>把gc导致停顿时间控制在我们指定的范围内
"-XXGxMixedGCCountTarget"
指一次混合回收过程中, 最后一个阶段执行几次垃圾混合回收,默认是8次, 意味这个阶段, <br>先停止系统运行, 混合回收部分region,恢复运行, 再停止系统运行, 混合回收region;<br>比如800region,一次回收100个,反复8次<br><br>为什么要反复多次呢? 为了达到最少停顿时间的要求
"-XX:G1HeapWastePercent"默认值5%
Mixed GC过程中, 对Region回收都是基于复制算法进行的, 都是把要回收的Region里的存活对象放入其他Region, 然后这个Region中的垃圾全部清理掉, 这个过程中不断有空出来的心的Region, 一旦这些空出来的Region数量达到堆内存的5%, 本次混合回收就结束了
"-XX:G1MinEDGCLiveThresholdPercent" 默认值85%
确定要回收region时候,必须是存活对象低于85%的region才可以回收,否则要是一个region的存活对象多余85%, 你还可以回收他干嘛呢?<br>拷贝85%的对象到别的region, 成本是很高
混合回收失败的时候Full GC
万一出现拷贝过程中发现没有空闲的region可以承载自己存活对象了, 就会触发一次失败, 一旦失败立马切换成停止系统程序, 然后采取单线程进行标记,清理和压缩整理, 空出来一个region, 这个过程是极慢极慢的