JVM之垃圾回收-垃圾收集器( 四 )


当新生代对象无法分配过大对象,就会放到老年代进行分配 。
G1收集器
上一代的垃圾收集器(串行, 并行, 以及CMS)都把堆内存划分为固定大小的三个部分: 年轻代(young ), 年老代(old ), 以及持久代( ) 。
注:堆内存中都可以认为是Java对象 。
G1(-First)是JDK7-u4才推出商用的收集器;
G1 (-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器 。以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征 。被视为JDK1.7中虚拟机的一个重要进化特征 。
G1的使命是在未来替换CMS,并且在JDK1.9已经成为默认的收集器 。
特点 并行与并发
G1能充分利用CPU、多核环境下的硬件优势,使用多个CPU(CPU或者CPU核心)来缩短stop-The-World停顿时间 。部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让java程序继续执行 。
分代收集
虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但是还是保留了分代的概念 。
空间整合
与CMS的“标记–清理”算法不同,G1从整体来看是基于“标记整理”算法实现的收集器;从局部上来看是基于“复制”算法实现的 。
可预测的停顿
这是G1相对于CMS的另一个大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型 。可以明确指定M毫秒时间片内,垃圾收集消耗的时间不超过N毫秒 。在低停顿的同时实现高吞吐量 。
问题 为什么G1可以实现可预测停顿 可以有计划地避免在Java堆的进行全区域的垃圾收集;G1收集器将内存分大小相等的独立区域(),新生代和老年代概念保留,但是已经不再物理隔离 。G1跟踪各个获得其收集价值大小,在后台维护一个优先列表;每次根据允许的收集时间,优先回收价值最大的(名称-First的由来);
这就保证了在有限的时间内可以获取尽可能高的收集效率;
一个对象被不同区域引用的问题
一个不可能是孤立的,一个中的对象可能被其他任意中对象引用,判断对象存活时,是否需要扫描整个Java堆才能保证准确?
在其他的分代收集器,也存在这样的问题(而G1更突出):回收新生代也不得不同时扫描老年代?
这样的话会降低Minor GC的效率;
解决方法:
无论G1还是其他分代收集器,JVM都是使用 Set来避免全局扫描:
每个都有一个对应的 Set;
每次类型数据写操作时,都会产生一个Write 暂时中断操作;
然后检查将要写入的引用指向的对象是否和该类型数据在不同的(其他收集器:检查老年代对象是否引用了新生代对象);
如果不同,通过把相关引用信息记录到引用指向对象的所在对应的 Set中;
当进行垃圾收集时,在GC根节点的枚举范围加入 Set;
就可以保证不进行全局扫描,也不会有遗漏 。
应用场景
具体什么情况下应用G1垃圾收集器比CMS好,可以参考以下几点(但不是绝对):
超过50%的Java堆被活动数据占用;对象分配频率或年代的提升频率变化很大;GC停顿时间过长(长于0.5至1秒);
建议:
设置参数
可以通过下面的参数,来设置一些G1相关的配置 。
指定使用G1收集器:"-XX:+UseG1GC"当整个Java堆的占用率达到参数值时,开始并发标记阶段;默认为45:"-XX:InitiatingHeapOccupancyPercent"为G1设置暂停时间目标,默认值为200毫秒:"-XX:MaxGCPauseMillis"设置每个Region大小,范围1MB到32MB;目标是在最小Java堆时可以拥有约2048个Region:"-XX:G1HeapRegionSize"新生代最小值,默认值5%:"-XX:G1NewSizePercent"新生代最大值,默认值60%:"-XX:G1MaxNewSizePercent"设置STW期间,并行GC线程数:"-XX:ParallelGCThreads"设置并发标记阶段,并行执行的线程数:"-XX:ConcGCThreads"