Garbage First收集器是垃圾收集的里程碑式的成果,开创了收集器面向局部收集的设计思路,和基于Region的内存布局形式。
面向局部收集: 在G1之前,几乎所有的垃圾收集器的目标范围要么是整个新生代,要么是整个老年代,要么是整个堆,而G1可以面向堆内存的任何部分来进行收集,可以把整个堆划分成任意个部分进行回收。
基于Region的内存布局: 基于Region的内存布局来实现面向局部收集的思路。他可以把连续的堆划分为多个大小相等的独立区域(Region),每个Region区域都可以根据需要来扮演Edin区或者Survivor区或者老年代,在根据这些角色匹配对应的回收算法。他还有一类特殊的区域是Humongous,专门用来存储大对象。取值范围是1MB~32MB。
Region里面的跨Region引用对象如何解决?
使用记忆集避免全堆作为GCRoots扫描,这些记忆集会记录下别的Region指向自己的指针,由于Region的区域会很多,因此记忆集的数量也很多,所以G1收集器要比之前的垃圾收集器内存占用更高。多耗费10%~20%。
并发标记如何保证收集线程和用户线程互不干扰的运行?
问题的关键是解决用户线程改变对象引用关系时,必须要保证不能打破原本的对象图结构,G1收集器是通过原始快照(SATB)算法来实现。
还有一个问题是对用户线程的影响体现在回收过程中新创建对象的内存分配上,G1为每个Region设计两个TAMS指针,把Region中的一部分空间划分出来用于并发回收过程中新对象创建。
怎样建立一个可靠的停顿预测模型?
衰减均值:G1会记录每个Region的回收耗时、每个记忆集的里面的数量,得出平均值、标准偏差、置信度等信息。这样在回收时根据用户设置的目标期望停顿时间,算出哪些Region组成的回收集才可以不超过期望停顿时间。
收集过程
初始标记->并发标记->最终标记->筛选回收
停顿时间一般要设置多少?
一般不能设置太小,比如设置20ms,可能会导致新生成的对象速度比回收的速度还快,垃圾慢慢堆积,运行时间一长,最终迫使Full GC反而降低性能,通常可以设置100ms~300ms比较合理。用户也不太能感知。
G1和CMS比较
G1标记整理,标记复制;CMS标记清除;G1不会产生内存碎片
G1比较消耗内存比如每个Region都有记忆集
小内存上CMS更好,大内存上(4G~6G)G1更好,G1最低4G内存
G1的一些参数
-XX:MaxGCPauseMills 允许收集停顿时间,默认200ms
-XX:G1HeapRegionSize 每个Region区域的大小 1~32MB