1.前言
今天得空,打开音乐。再来一篇JVM中核心的技术(垃圾收集器)。
2.堆内存结构
年轻代(young generation) 包括eden ,存活区S0,S1,
年老代(old generation),
持久代(permanent generation).
3.垃圾收集器种类
串行serial,
并行parallel,
CMS,
G1(Garbage-First)
4.G1收集器新的内存结构
G1收集器采用不同的内存结构划分,将堆内存划分为固定大小的多个区域。
每个区的大小在jvm启动时初始化。通常会划分2000左右个区,每个区大小根据jvm设置的堆内存平均分配,每个区的大小范围1MB到32Mb。每个区相应的映射到对应的老年代,新生代(年轻代),存活区。

好处:划分为多个区域,可以进行并行收集操作
5.G1年轻代GC过程
首先会扫描年轻代存活的对象,将其copy转移到存活区。如果对象存活的时间到达了jvm设置的阈值,将会转移到老年代。
注意:此时会进行一次STW(stop the world)事件。目的是为了计算新生代和存活区的大小,为下一次年轻代GC做准备。
GC完成后,存活对象就被转移到存活区,或者老年区。等待下一次GC来临。
6.G1老年代GC过程
老年代的收集和其他的收集器过程相似,分为多步执行。其中会进行多次STW事件。
1.初始标记(Initial Mark)
此时会进行STW事件,在G1中,是附加在年轻代GC时,标记可能有引用是指向老年代的对象。
2.扫描根区域(Root Region Scanning)
扫描存活区中指向老年代的引用对象,此时程序会继续运行,不会STW事件(可能会造成运行中增加了对老年区的引用,或者减少了对老年区的引用。所以需要下一阶段,再次标记),此阶段必须在年轻代GC之前完成(不然标记的对象都被清除了,还标记个锤子)
3.并发标记(Concurrent Marking)
扫描堆中还存活的所有对象,如果此时执行年轻代GC,则会打断此操作
4.再次标记(Remark)
此步是核心步骤,会先STW,然后标记堆中存活的所有对象,{据说使用了SATB(snapshot-at-the-beginning)起始快照算法标记,比传统的CMS使用的算法还快速}。此时所有标记已全部完成,下面就是进行清理无引用对象和转移存活对象了。
5.清理(Cleanup)
清理除标记外的区域(包括老年代和年轻代),G1会首先选择那些活跃度低的区清理。
6.拷贝(Copying)
将标记存活的对象收集,压缩到存活区中。此时整个老年代GC完成
7.总结
1.G1对于堆内存空间,是划分为多个区的。
2.年轻代内存,老年代内存。都是由一组不连续的区组成的
3.年轻代收集,叫做young GCs,会发生STW事件。
4.年轻代GC是多线程并行操作
5.老年代GC会根据区活跃度来标识
6.老年代再次标记(核心阶段)使用SATB算法,空的区会被直接回收
7.老年代GC时,会连带年轻代一起GC。
8.常用命令
-XX:+UseG1GC
使用G1收集器进行收集
-XX:MaxGCPauseMillis=200
GC最大停顿事件(JVM会尽力满足此数值,其中最影响这个数值的就是STW事件,因为需要停掉所有工作线程,去执行标记或者GC此时应用处于阻塞状态)
-XX:InitiatingHeapOccupancyPercent=45
启动时GC的阈值,当堆内存使用量达到这个数值的百分比时,进行GC
9.结语
本文完结。其中有很多知识是自己之前面试,或者挖掘底层知识体系时或多或少接触的东西。希望对你有帮助。
总结,升华自己的生活。谢谢O(∩_∩)O哈哈~




