小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
G1开创“面向局部收集的设计思路”和“基于Region的堆内存布局形式”。
基于Region的堆内存布局
把连续的Java堆划分为多个大小相等的独立区域,Region根据需要扮演新生代或者老年代,收集器根据不同角色的Region采用不同处理策略。
Humongous区域
Humongous区域用于存储大对象,G1认为只要大小超过一个Region容量一半的对象即可判定为大对象,每个Region的大小通过参数-XX: G1HeapRegionSize
设定,范围为1MB~32MB。对于超过整个Region的超级大对象,会存放在连续的Humongous中,对于Humongous区域,垃圾收集的行为与对待老年代相同。
G1解决的问题
跨代引用
由于垃圾收集是以Region为基本单位的,因此必须知道哪些其他Region中有对该Region的引用。对此G1维护了一个Map,Key为其他Region的起始地址,Value是卡表索引号的集合。通过Key可以判断有哪些Region引用了我,通过Value可以查出具体引用了哪些对象。
并发标记阶段用户线程和收集线程不干扰
G1通过原始快照的方式来解决,即当出现“删除全部灰色对象到白色对象的引用”时,将删除的引用关系记录下来,并发扫描后再进行一次搜索。
新创建对象的内存分配
Region中有两个TAMS指针,把Region中的一块内存划分出来用于并发回收过程中的新对象分配,所有新对象都分配到这块内存中,默认为存过,不纳入回收范围。如果内存回收速度赶不上内存分配速度,G1也要冻结用户线程的执行,导致Full GC而长时间STW。