垃圾回收器"/>
【JVM】之垃圾回收器
目录
垃圾回收器
垃圾回收器的分类
GC性能指标
HotSpot垃圾回收器
Parallel Scavenge回收器(JDK1.8默认使用):吞吐量优先
Parallel Scavenge特点:
Parallel是并行的垃圾回收器,吞吐量很高,适应场景:
Parallel Old特点
CMS垃圾回收器
概述
垃圾回收过程
三色标记算法
CMS垃圾回收的时机
总结
G1回收器
概述
为什么名字叫做 区域化分代式(G1)呢?
收集过程
G1的优点
G1的缺点
G1总结
垃圾回收器
垃圾回收算法是一些针对不同的区域不同的场景设计的合理方法,而垃圾回收器是这些算法的执行者。
垃圾回收器的分类
根据线程的数量来分:
单线程(串行)垃圾回收器 :Serial、Serial Old;
多线程(并行)垃圾回收器:Parnew、Parallel Scavenge、Parallel Old。
根据工作内存来分:
新生代垃圾回收器:Serial、Parnew、Parallel Scavenge;
老年代垃圾回收器:Serial Old、Parallel Old、CMS。
根据工作模式分:
独占式垃圾回收器:Serial、Parnew、Parallel Scavenge;
并发式垃圾回收器:CMS、G1。
GC性能指标
STW时间 : (“Stop The World”)垃圾回收时暂停用户线程的时间。
吞吐量 : 用户线程运行时间/(用户线程运行时间+垃圾回收时间)。
垃圾收集开销:吞吐量的补数,垃圾回收时间/用户线程运行时间+垃圾回收时间。
内存占用:Java堆区多占用的内存大小。
快速:一个对象从诞生到被回收的时间。
GC性能指标主要看吞吐量和STW停顿时间。并且吞吐量和STW停顿时间是相互矛盾的,只能折中考虑。
各个垃圾回收器的特点也不一样,有的追求吞吐量,有的追求STW停顿时间。一般在不同的场合采用不同的垃圾回收器。比如与用户交互较多的场景中追求低延迟,因此要求STW时间较少;而后台程序就比较追求吞吐量。
HotSpot垃圾回收器
图中展示了 7 种作用于不同分代的收集器,如果两个收集器之间存在连线, 则说明它们可以搭配使用。虚拟机所处的区域则表示它是属于新生代还是老年代收集器。
Parallel Scavenge回收器(JDK1.8默认使用):吞吐量优先
Parallel Scavenge又称Parallel。Paralle并行;Scavenge捡破烂,拾荒
Parallel Scavenge特点:
1.年轻代使用复制算法、并行回收、STW机制。 2.吞吐量可控制。 3.拥有自适应调节策略(能够根据程序需求自动分配内存空间)。 4.回收年轻代的并行垃圾回收器。
Parallel是并行的垃圾回收器,吞吐量很高,适应场景:
适合与用户交互较少,后台计算的场景。 例如:执行批量处理、订单处理、工资支付等等,或者服务器端。
Parallel Old特点
作用在老年代,和Parallel配合使用 采用标记-压缩算法、并行回收、STW机制
CMS垃圾回收器
概述
CMS(Concurent Mark Sweep)收集器,是追求低停顿,与用户线程并发执行的收集器。
是一款首创的与用户并发运行的收集器。
垃圾回收过程
初始标记: STW(时间较短),使用一条初始标记线程对GCRoots直接关联的所有对象进行标记。
并发标记:与用户线程并发执行,此阶段进行可达性分析,标记处所有垃圾对象。
重新标记:STW(时间较短),使用多条标记线程,将刚刚没有标记的垃圾对象全部标记出来。
并发清除:只使用一条GC线程与用户线程并发执行,清理所标记出来的垃圾对象。此过程比较耗时。(多线程都比较耗时)。
CMS的俩个阶段采用并发执行,是为了追求低延迟,在垃圾回收的同时也要处理用户请求。
CMS优点: 可以并发收集,低延迟。
CMS缺点:
CMS基于标记-清除算法,因此会产生内存碎片,当大作业到来时,可能会提前触发Full GC。
CMS在并发阶段,耗时较长,总吞吐量会降低。
CMS无法清理浮动垃圾。
PS:标记-清除算法会产生垃圾碎片,那么会什么不适用标记-压缩算法呢?
标记-压缩算法是需要移动对象的,但是CMS在清理垃圾的时候是与用户线程并发执行的。
浮动垃圾:CMS标记垃圾和清除垃圾都是和用户线程并发执行,这时用户线程产生的新垃圾对象就是浮动对象。这些对象在本次垃圾回收是无法被清理掉的。
三色标记算法
由于CMS使用并发执行,其他用户线程就可能会使原来标记的引用链改变,针对这个问题,CMS采用三色标记算法,将所有对象分为3中颜色(对应三种状态)。
黑色:例如GCRoots根对象,该对象已经被标记过了,并且该对象的所有属性也被标记了(这些属性被标记为灰色)。
灰色:对象已经被垃圾回收器 扫描过了,但其下的属性还没有被标记,这些对象被标记为灰色。
白色:过完整的标记算法后还没有被标记的对象就是不可触及的,被标记为白色,认定为垃圾。
过程
1.刚开始,GCRoots会被标记为黑色。
2.将GCRoots直接关联的对象标记为灰色。
3.将灰色标记为黑色,并且这些灰色对象的直接关联对象标记为灰色。
4.重复2、3步骤,直至没有灰色对象为止。
5.黑色对象判定为存活对象,白色的判定为垃圾。
这个过程在进行的时候,其他用户线程也会进行,就有可能出现漏标与错标的问题。
漏标:
比如现有三个对象A、B、C,当A为黑色对象,B为灰色对象时,GC线程扫描B对象时,其他用户线程断开了A和B之间的引用关系(并且其他地方没有引用B),按道理B以及它的属性都应该判定为垃圾对象,但是垃圾回收器在扫描B,B已经是灰色对象,所以它会被判定为黑色,它的恶属性被判定为灰色,这种情况就会把B漏标,垃圾回收时,也不会被清理。
错标:
比如现有三个对象A、B、C,当A为黑色对象,B为灰色对象时,GC线程扫描B对象之前,用户线程将C引用赋给了A,并且断开了与B的关联,这是GC线程扫描B是就无法触及到C,A为黑色对象,GC线程本次也不会扫描了,就会导致C对象变成不可触及的垃圾对象。在其他用户线程再次访问C对象时,发现找不到,就会报空指针异常。
解决错标的方法
上述错标问题,有俩部分原因共同造成,只要打破这俩个条件之一,就能够阻止错标的发生。
原始快照:当灰色对象与白色对象断开连接时,将这条记录下来,扫描结束后,将记录中的灰色对象再次扫描。
增量更新:当黑色对象与白色对象建立连接时,将这条记录下来,扫描结束后,将记录中的黑色对象再次扫描。
CMS垃圾回收的时机
由于CMS采用并发的手段,虽然低延迟,但是整个回收过程较长,并且由于垃圾回收的同时用户线程依然会申请内存,那么就不能等到内存不足时才开始。
当堆内存达到一定的阈值时,就要开始垃圾回收。如果JVM预留的内存无法满足用户进程的需要,那么就会出现一次“Concurrent Mode Failure”失败,这时虚拟机将启用备用方案:启用Serial Old来对老年代回收,这样STW就会很长。
总结
CMS中的GC作为守护线程与用户线程并发执行,由于用户线程随时会更改随想的引用关系,就增大了CMS的工作负担,因此CMS较为复杂。解决这个问题CMS引入了三色标记算法,将这些引用关系的修改记录下来,以便在重新标记阶段再次扫描修正引用关系。
由于CMS仍然存在很多缺陷,所以JVM没有将CMS作为默认垃圾回收器,但CMS已经开辟了GC与用户线程并发执行的先河。
G1回收器
概述
G1(Garbage First):是一款垃圾优先的回收器,是能够降低STW时间同时兼顾了吞吐量的“全功能收集器”。它是面向服务器端的回收器。
为什么名字叫做 区域化分代式(G1)呢?
因为G1将堆内存分为很多更小的(Region)区域(物理上不连续,逻辑上连续),然后有计划地对堆内存进行垃圾回收,回收时,优先回收垃圾最多的区域。即采用垃圾优先(Garbage First的原则。
G1是一款面向服务器端应用的垃圾回收器,主要针对多核CPU以及内存较大的机器,能够满足STW时间的前提下还能兼顾高的吞吐量。因此对机器的性能也有很高的硬性要求。
收集过程
收集过程的标记阶段与CMS的基本相同,但是在回收阶段,是单线程执行,暂停其他线程,在一定的时间内对回收价值大的区域进行垃圾回收。
适用场景:对STW时间有一定的控制,内存大的应用。
G1的优点
1.并行与并发
并行:多个GC线程同时工作。
并发:部分工作与用户线程交替并发执行,因此不会再整个回收阶段出现完全发生阻塞的情况。
2.分代收集
虽然G1将堆内存分为多个Region,但是这些Region在逻辑上依然区分新生代和老年代。并且G1既可以回收年轻代也可以回收老年代。而在物理结构上,整个年轻代或者老年代是连续的。
3.空间整合
G1是以Region为单位进行的,在Region采用复制算法,但是整体上可以看做是标记-压缩算法的,这里种算法都可以整理内存碎片,这种特性有利于程序的长时间运行,大大降低了分配大对象时没有足够连续的内存空间而触发GC的概率。
java对空间越大,G1的优势更明显。
4.可预测的停顿时间模型
G1除了追求低停顿意外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M的时间内,垃圾回收的时间最多为N。
由于分区的原因,G1每次的垃圾回收只针对部分区域,缩小了垃圾回收的范围,这对于全局停顿时间的控制也能得到很好的控制。
G1跟踪各个Region里面的垃圾堆积价值大小,并维护一个队列,每次选择一个价值最大的Region进行回收。这样保证了G1垃圾回收效率,在有限的时间内可以获取更高的收集效率。
G1的缺点
相比较于CMS,G1还不具备全方位、压倒性的优势。不如在用户线程运行过程中,G1额外的占用内存以及额外执行负载都比CMS要高。
G1会对年轻代频繁的GC,在GC过程会Eden区扫描,但是有些新对象是被老年区的对象所引用,但是G1不可能对所有对空间都进行扫描,那样就失去了分区的意义。因此,G1使用了一个Remeber Set来记录引用关系,而Rset也是占用堆内存的。
在垃圾回收时,如果用户线程改变了年轻代的引用关系,为了确保引用关系的正确的同时保证吞吐量,还需要用Dirty Card Queue(脏卡队列)来记录引用关系。
对于小内存的应用,CMS的性能会比较表现会大概率优先于G1。
G1总结
G1是一款保证低延迟的前提下,有保证了更大的吞吐量,是一款“全功能垃圾回收器”。JDK9版本用G1淘汰了CMS。内存空间越大,G1的优势越明显,更适合与内存较大的场景。符合内存造价越来越低的大环境。
更多推荐
【JVM】之垃圾回收器
发布评论