为解决CMS算法产生空间碎片和其它一系列的问题缺陷,HotSpot提供了另一种垃圾回收策略,G1(Garbage First)算法,经过参数 -XX:+UseG1GC
来启用,该算法在JDK 7u4版本被正式推出算法
G1垃圾收集算法主要应用在多CPU大内存的服务中,在知足高吞吐量的同时,竟可能的知足垃圾回收时的暂停时间,该设计主要针对以下应用场景:(多CPU,大内存,高吞吐,尽量GC短暂暂停)并发
垃圾收集线程和应用线程并发执行,和CMS同样性能
空闲内存压缩时避免冗长的暂停时间ui
应用须要更多可预测的GC暂停时间spa
不但愿牺牲太多的吞吐性能线程
不须要很大的Java堆 (翻译的有点虚,多大才算大?)翻译
在G1算法中,堆内存被划分为多个大小相等的内存块(Region),每一个Region是逻辑连续的一段内存。设计
其它GC算法内存space必须是地址连续的空间。code
每一个Region被标记了E(eden)、S(survivor)、O(old)和H(humongous),对象
说明每一个Region在运行时都充当了一种角色,其中H是以往算法中没有的,它表明Humongous,这表示这些Region存储的是巨型对象(humongous object,H-obj),当新建对象大小超过Region大小一半时,直接在新的一个或多个连续Region中分配,并标记为H。
堆内存中一个Region的大小能够经过 -XX:G1HeapRegionSize
参数指定,大小区间只能是1M、2M、4M、8M、16M和32M,总之是2的幂次方,若是G1HeapRegionSize为默认值,则在堆初始化时计算Region的实践大小,默认把堆内存按照2048份均分,最后获得一个合理的大小。
G1中提供了三种模式垃圾回收模式,young gc、mixed gc 和 full gc,在不一样的条件下被触发。
发生在年轻代的GC算法,通常对象(除了巨型对象)都是在eden region中分配内存,当全部eden region被耗尽没法申请内存时,就会触发一次young gc,这种触发机制和以前的young gc差很少,执行完一次young gc,活跃对象会被拷贝到survivor region或者晋升到old region中,空闲的region会被放入空闲列表中,等待下次被使用。
当愈来愈多的对象晋升到老年代old region时,为了不堆内存被耗尽,虚拟机会触发一个混合的垃圾收集器,即mixed gc,该算法并非一个old gc,除了回收整个young region,还会回收一部分的old region,这里须要注意:是一部分老年代,而不是所有老年代,能够选择哪些old region进行收集,从而能够对垃圾回收的耗时时间进行控制。
那么mixed gc何时被触发?
先回顾一下cms的触发机制,若是添加了如下参数:
-XX:CMSInitiatingOccupancyFraction=80
-XX:+UseCMSInitiatingOccupancyOnly
当老年代的使用率达到80%时,就会触发一次cms gc。
相对的,mixed gc中也有一个阈值参数 -XX:InitiatingHeapOccupancyPercent
,当老年代大小占整个堆大小百分比达到该阈值时,会触发一次mixed gc.
mixed gc的执行过程有点相似cms,主要分为如下几个步骤:
initial mark: 初始标记过程,整个过程STW,标记了从GC Root可达的对象
concurrent marking: 并发标记过程,整个过程gc collector线程与应用线程能够并行执行,标记出GC Root可达对象衍生出去的存活对象,并收集各个Region的存活对象信息
remark: 最终标记过程,整个过程STW,标记出那些在并发标记过程当中遗漏的,或者内部引用发生变化的对象
clean up: 垃圾清除过程,若是发现一个Region中没有存活对象,则把该Region加入到空闲列表中
若是对象内存分配速度过快,mixed gc来不及回收,致使老年代被填满,就会触发一次full gc,G1的full gc算法就是单线程执行的serial old gc,会致使异常长时间的暂停时间,须要进行不断的调优,尽量的避免full gc.
https://mp.weixin.qq.com/s/K7T8vjiHEwwN8uiXVLI6AQ
https://mp.weixin.qq.com/s/bHx0K4BRaHsmDSV0oxqf_Q