目录
1.G1垃圾收集器
1.1 垃圾回收过程
?1.2 G1垃圾收集分类
1.3 G1收集器核心参数手册
2.ZGC垃圾收集器(面试不考)
2.1 ZGC的内存布局
?2.2 ZGC的架构NUMA模型
2.3 ZGC运作过程
?2.4 颜色指针和读屏障
1.G1垃圾收集器
G1垃圾收集器是一款面向多CPU,大内存的垃圾收集器,内部采用region内存块的概念,将内存块分为多个,里面将内存块划分为Eden,survivor,old,humongous(大对象存储)区域。并不是连续的区域。
------
内存划分举例:
4G的JVM占比,一个region大小:4*1024/2048(默认2048个region)=2M。
年轻代占比默认初始值5%=4096*5%=204.8M,最大不会超过60%=4096*0.6=2457.6M
年轻代Eden:s0:s1默认=8:1:1
------
G1参数:
region大小:-XX:G1HeapRegionSize,可以指定,但是推荐默认
设置年轻代初始大小:-XX:G1NewSizePercent
设置年轻代最大大小:-XX:G1MaxNewSizePercent
-------
G1新增的一块区域Humongous,专门用来放大对象,如果一个对象在放入eden区时判断如果超过一块Region的50%就将对象放入Humongous区域,如果很大,就将一块连续的Region内存块分配给Humongous
-------
G1采用复制算法,比如有个old区域的内存块,会将其复制到相邻的未使用的内存块中,然后清除这个内存块,效果类似于标记整理算法,不会产生不连续的内存碎块。
-------
G1会维护一个优先列表,比如一块Old内存块回收需要200ms,另一块50ms,G1会优先回收50ms的内存块。
-------
优化建议:-XX:MaxGCPauseMills值建议使用默认值200ms,如果业务很敏感可以设置小一点50ms
-------
使用场景:
1. 50%以上的堆被存活对象占用
2. 对象分配和晋升的速度变化非常大
3. 垃圾回收时间特别长,超过1秒
4. 8GB以上的堆内存(建议值)
5. 停顿时间是500ms以内
-------
JVM内存选取案例:
4G以下可以用parallel,4-8G可以用ParNew+CMS,8G以上可以用G1,几百G以上用ZGC
-------
每秒几十万并发如何优化JVM案例:
使用G1垃圾收集器,常用的kafaka消息中间件需要的内存一般都在64G,一般都是朝生夕死的对象,把年轻代大小划分的大点。
?
1.1 垃圾回收过程
初始标记(initial mark,STW):跟CMS一样,标记GC ROOTS下面的所有直接对象
并发标记(Concurrent Mark):跟CMS一样
最终标记(final mark,STW):跟CMS一样
筛选回收(Cleanup,STW):跟CMS不同的一点是这一步也是STW的,在回收时默认G1里面有一个最大STW时间=初始标记STW+最终标记STW+筛选回收STW的总和,如果要回收的对象很大,比如回收1000个Region内存块,但是STW只有200ms,只能回收800个Region内存块,这一次GC就只回收800个,剩下的200个下次GC回收。
-XX:MaxGCPauseMillis:STW停顿时间,默认200ms
?
?1.2 G1垃圾收集分类
Minor GC:当Eden放满内存的5%以后会计算是否超过-XX:MaxGCPauseMillis设置最大停顿时间,如果超过才会minorGC。
Mixed GC: 当老年代大小超过(-XX:InitiatingHeapOccupancyPercent)设置的值时会回收所有的年轻代和部分老年代对象,大对象也会回收。默认45%
Full GC:如果没有足够的空间用来复制老年代对象时会触发Full GC会使用单线程收集垃圾对象。
1.3 G1收集器核心参数手册
-XX:+UseG1GC:使用G1收集器
-XX:ParallelGCThreads:指定GC工作的线程数量
-XX:G1HeapRegionSize:指定分区大小(1MB~32MB,且必须是2的N次幂),默认将整堆划分为2048个分区
-XX:MaxGCPauseMillis:目标暂停时间(默认200ms)
-XX:G1NewSizePercent:新生代内存初始空间(默认整堆5%)
-XX:G1MaxNewSizePercent:新生代内存最大空间
-XX:TargetSurvivorRatio:Survivor区的填充容量(默认50%),Survivor区域里的一批对象(年龄1+年龄2+年龄n的多个
年龄对象)总和超过了Survivor区域的50%,此时就会把年龄n(含)以上的对象都放入老年代
-XX:MaxTenuringThreshold:最大年龄阈值(默认15)
-XX:InitiatingHeapOccupancyPercent:老年代占用空间达到整堆内存阈值(默认45%),则执行新生代和老年代的混合
收集(
MixedGC
),比如我们之前说的堆默认有2048个region,如果有接近1000个region都是老年代的region,则可能
就要触发MixedGC了
-XX:G1MixedGCLiveThresholdPercent(默认85%) region中的存活对象低于这个值时才会回收该region,如果超过这
个值,存活对象过多,回收的的意义不大。
-XX:G1MixedGCCountTarget:在一次回收过程中指定做几次筛选回收(默认8次),在最后一个筛选回收阶段可以回收一
会,然后暂停回收,恢复系统运行,一会再开始回收,这样可以让系统不至于单次停顿时间过长。
-XX:G1HeapWastePercent(默认5%): gc过程中空出来的region是否充足阈值,在混合回收的时候,对Region回收都
是基于复制算法进行的,都是把要回收的Region里的存活对象放入其他Region,然后这个Region中的垃圾对象全部清
理掉,这样的话在回收过程就会不断空出来新的Region,一旦空闲出来的Region数量达到了堆内存的5%,此时就会立
即停止混合回收,意味着本次混合回收就结束了。
?
2.ZGC垃圾收集器(面试不考)
参考文章:
https://wiki.openjdk.java.net/display/zgc/Main
http://cr.openjdk.java.net/~pliden/slides/ZGC-Jfokus-2018.pdf
?ZGC的目标:
1.支持TB级别的JVM,现支持4TB-16TB
2.STW停顿时间10ms以内
3.奠定未来GC的基础
4.最糟糕的情况下吞吐量会下降15%,可以通过扩容解决。
-----
ZGC触发时机
ZGC目前有4种机制触发GC:
定时触发,默认为不使用,可通过ZCollectionInterval参数配置。
预热触发,最多三次,在堆内存达到10%、20%、30%时触发,主要时统计GC时间,为其他GC机制使用。
分配速率,基于正态分布统计,计算内存99.9%可能的最大分配速率,以及此速率下内存将要耗尽的时间点,
在耗尽之前触发GC(耗尽时间 - 一次GC最大持续时间 - 一次GC检测周期时间)。
主动触发,(默认开启,可通过ZProactive参数配置) 距上次GC堆内存增长10%,或超过5分钟时,对比距上
次GC的间隔时间跟(
49 * 一次GC的最大持续时间),超过则触发。
?
2.1 ZGC的内存布局
?ZGC的Region可以具有如图3-19所示的大、 中、 小三类容量:
小型Region(
Small Region) : 容量固定为2MB, 用于放置小于256KB的小对象。
中型Region(Medium Region) : 容量固定为32MB, 用于放置大于等于256KB但小于4MB的对象。
大型Region(
Large Region) : 容量不固定, 可以动态变化, 但必须为2MB的整数倍, 用于放置4MB或
以上的大对象。 每个大型Region中
只会存放一个大对象, 这也预示着虽然名字叫作“大型Region”, 但它的实际容量完全有可能小于中型
Region, 最小容量可低至4MB。 大型Region在ZGC的实现中是不会被重分配(重分配是ZGC的一种处理动作,
用于复制对象的收集器阶段, 稍后会介绍到)的, 因为复制一个大对象的代价非常高昂
?
?2.2 ZGC的架构NUMA模型
UMA:多个CPU只有一个内存条,在访问时需要涉及到内存的竞争,有锁就会影响效率。
NUMA:每个CPU都有一块内存。
2.3 ZGC运作过程
并发标记:跟G1的类似,只是在下图初始标记和最终标记有一段些微的停顿。
并发预备重分配:计算要回收的对象
并发重分配:采用复制算法将要回收的对象复制到未使用的内存块中,并维护一个转发表,记录旧对象到新对象之间的关系。
并发重映射:修正并发重分配阶段指向旧对象的所有引用,这个过程不是很迫切,一般会等到下一次GC时会重新遍历一次一起修复。
?
?2.4 颜色指针和读屏障
?颜色指针,ZGC的核心设计之一,以前的GC信息保存在对象头上,现在保存在指针上。
可以支持2^42=4T内存。
每个对象有一个64位指针,这64位被分为:
18位:预留给以后使用;
1位:Finalizable标识,此位与并发引用处理有关,它表示这个对象只能通过finalizer才能访问;
1位:Remapped标识,设置此位的值后,对象未指向relocation set中(
relocation set表示需要GC的
Region集合);
1位:Marked1标识;
1位:Marked0标识,和上面的Marked1都是标记对象用于辅助GC;
42位:对象的地址(所以它可以支持2^42=4T内存):
?
?
|