APP下载
报价宝  ›  科技  › 

JVM中垃圾收集演算法及垃圾收集器详解

报价宝 来源:baojiabao.com 发布时间:2019-10-12 17:54:00 10月08日更新
报价宝综合消息JVM中垃圾收集演算法及垃圾收集器详解

Java中的垃圾回收机制,一直是Java的一大特性,不需要自己回收,Java虚拟机器会自动处理。但是我们仍要理解垃圾收集机制,知道其原理和实现方式,这样才能更好地让垃圾回收机制工作,更好地维护我们的专案。

一、垃圾收集算法

1.标记-清除算法

最基础的收集算法是“标记-清除”(Mark-Sweep)算法,如同它的名字一样,算法分为“标记”和“清除”两个阶段。

①首先标记出所有需要回收的物件

②在标记完成后统一回收所有被标记的物件。

不足:

效率问题:标记和清除两个过程的效率都不高

空间问题:标记清除之后产生大量不连续的内存碎片,空间碎片太多可能会导致以后程式执行过程中需要分配较大物件时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

2.复制算法

目的:为了解决效率问题。

将可用内存按容量大小划分为大小相等的两块,每次只使用其中的一块。当一块内存使用完了,就将还存活着的物件复制到另一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况。

缺点:将内存缩小为了原来的一半。

现代的商业虚拟机器都采用这种收集算法来回收新生代,IBM公司的专门研究表明,新生代中物件98%物件是“朝生夕死”的,所以不需要按照1:1的比例来划分内存空间,而是将内存分为较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。HotSpot虚拟机器中预设Eden和Survivor的大小比例是8:1。

3.标记-整理算法

复制收集算法在物件存活率较高时,就要进行较多的复制操作,效率就会变低。

根据老年代的特点,提出了”标记-整理“算法。

标记过程仍然与”标记-清除“算法一样,但后续步骤不是直接对可回收物件进行清理,而是让所有存活的物件都向一端移动,然后直接清理掉边界以外的内存。

4.分代收集算法

一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。

在新生代中,每次垃圾收集时都发现有大批物件死去,只有少量存活,那就选用复制算法。

在老年代中,因为物件存活率高、没有额外空间对它进行分配担保,就必须采用“标记-清除”或“标记-整理”算法来进行回收。

二、垃圾回收机制的一些知识

1.JVM中的年代

JVM中分为年轻代(Young generation)和老年代(Tenured generation)。

HotSpot JVM把年轻代分为了三部分:1个Eden区和2个Survivor区(分别叫from和to)。预设比例为8:1,为啥预设会是这个比例,接下来我们会聊到。

一般情况下,新建立的物件都会被分配到Eden区(一些大物件特殊处理),这些物件经过第一次Minor GC后,如果仍然存活,将会被移到Survivor区。物件在Survivor区中每熬过一次Minor GC,年龄就会增加1岁,当它的年龄增加到一定程度时,就会被移动到年老代中。

因为年轻代中的物件基本都是朝生夕死的(80%以上),所以在年轻代的垃圾回收算法使用的是复制算法,复制算法的基本思想就是将内存分为两块,每次只用其中一块,当这一块内存用完,就将还活着的物件复制到另外一块上面。复制算法不会产生内存碎片。

在GC开始的时候,物件只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。紧接着进行GC,Eden区中所有存活的物件都会被复制到“To”,而在“From”区中,仍存活的物件会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设定)的物件会被移动到年老代中,没有达到阈值的物件会被复制到“To”区域。经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有物件移动到年老代中。

2.Minor GC和Full GC的区别

Minor GC:指发生在新生代的垃圾收集动作,该动作非常频繁。

Full GC/Major GC:指发生在老年代的垃圾收集动作,出现了Major GC,经常会伴随至少一次的Minor GC。Major GC的速度一般会比Minor GC慢10倍以上。

3. 空间分配担保

在发生Minor GC之前,虚拟机器会先检查老年代最大可用的连续空间是否大于新生代所有物件的总空间,如果这个条件成立,那么Minor GC可以 确保是安全的。如果不成立,则虚拟机器会检视HandlePromotionFailure设定值是否允许担保失败。如果允许,那会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代物件的平均大小,如果大于,则将尝试进行一次Minor GC,尽管这个Minor GC是有风险的。如果小于,或者HandlePromotionFailure设定不允许冒险,那这时也要改为进行一次Full GC。

以上便是在垃圾回收过程中,需要了解的一些必要的知识。下面我们就来介绍具体的垃圾收集器。

三、垃圾收集器

上图展示了7种作用于不同分代的收集器,如果两个收集器之间存在连线,说明它们可以搭配使用。

1.Serial收集器

是最基本、发展历史最悠久的收集器。这是一个单执行绪收集器。但它的“单执行绪”的意义并不仅仅说明它只会使用一个CPU或一条收集执行绪去完成垃圾收集工作,更重要的是它在进行垃圾收集时,必须暂停其他所有的工作执行绪,直到它收集结束。

是虚拟机器执行在Client模式下的预设新生代收集器。

优势:简单而高效(与其他收集器的单执行绪比),对于限定单个CPU的环境来说,Serial收集器由于没有执行绪互动的开销,专心做垃圾收集自然可以获得最高的单执行绪效率。

2.ParNew收集器

ParNew收集器其实就是Serial收集器的多执行绪版本。

是许多执行在Server模式下的虚拟机器中首选的新生代收集器,其中一个与效能无关但很重要的原因是,除了Serial收集器外,目前只有它能与CMS收集器配合工作。

ParNew收集器预设开启的收集执行绪数与CPU的数量相同。

下图是ParNew/Serial Old收集器执行示意图

3.Parallel Scavenge收集器

Parallel Scavenge收集器是一个新生代收集器,使用复制算法,又是并行的多执行绪收集器。

最大的特点是:Parallel Scavenge收集器的目标是达到一个可控制的吞吐量。

所谓吞吐量就是CPU用于执行使用者程式码的时间与CPU总消耗时间的比值,即吞吐量=执行使用者程式码时间/(执行使用者程式码时间+垃圾收集时间)。

高吞吐量则可以高效率地利用CPU时间,尽快完成程式的运算任务,主要适合在后台运算而不需要太多互动的任务。

4.Serial Old收集器

Serial Old是Serial收集器的老年代版本,同样是一个单执行绪收集器,使用“标记-整理”算法。这个收集器的主要意义也是在于给Client模式下虚拟机器使用。

如果在Server模式下,它主要还有两大用途:

1.与Parallel Scavenge收集器搭配使用

2.作为CMS收集器的后备预案,在并发收集发生Conurrent Mode Failure使用。

5.Parallel Old收集器

Parallel Old是Parallel Scavenge收集器的老年代版本,使用多执行绪和“标记-整理”算法。

在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge+Parallel Old收集器

6.CMS(Concurrent Mark Sweep)收集器

是HotSpot虚拟机器中第一款真正意义上的并发收集器,它第一次实现了让垃圾收集执行绪与使用者执行绪同时工作。

关注点:尽可能地缩短垃圾收集时使用者执行绪的停顿时间。

CMS收集器是基于“标记-清除”算法实现的,整个过程分为4个步骤:

①初始标记

②并发标记

③重新标记

④并发清除

其中,初始标记,重新标记这两个步骤仍然需要“Stop The World”。初始标记仅仅只标记一下GC Roots能直接关联到的物件,速度很快。并发标记阶段就是 进行GC Roots Tracing的过程。

重新标记阶段则是为了修正并发标记期间因使用者程式继续运作而导致标记产生变动的那一部分物件的标记概率,这个阶段的停顿时间一般会比初始标记阶段稍长,但远比并发标记时间短。

整个过程耗时最长的阶段是并发标记,并发清除过程,但这两个过程可以和使用者执行绪一起工作。

缺点:

①CMS收集器对CPU资源非常敏感。在并发阶段,它虽然不会导致使用者执行绪停顿,但是会因为占用了一部分执行绪(或者说CPU资源)而导致应用程序变慢,总吞吐量会降低。

②CMS收集器无法处理浮动垃圾,可能出现“Conurrent Mode Failure”失败而导致另一次Full GC的产生。由于CMS并发清理阶段使用者执行绪还在执行着,伴随程式执行自然就还会产生新的垃圾,这一部分垃圾出现在标记过程之后,CMS无法在档次收集中处理掉它们,只好留待下一次GC时再清理掉。这部分垃圾就称为“浮动垃圾”。因此CMS收集器不能像其他收集器那样等到老年代几乎完全被填满了再进行收集,需要预留一部分空间提供并发收集时程式运作使用。在JDK1.5的预设设定下,CMS收集器当老年代使用了68%的空间后就会被启用。如果预留空间无法满足程式需要,就会出现一次“Concurrent Mode Failure”失败,这时虚拟机器将启动后备预案Serial Old。

③CMS是一款基于“标记-清除”算法实现的收集器,所以会有大量空间碎片问题。

7.G1收集器

是当今收集器技术发展的最前沿成果之一。是一款面向服务端应用的垃圾收集器。

特点:

①并行与并发

能充分利用多CPU,多核环境下的硬件优势,缩短Stop-The-World停顿的时间,同时可以通过并发的方式让Java程式继续执行

②分代收集

可以不需要其他收集器的配合管理整个堆,但是仍采用不同的方式去处理分代的物件。

③空间整合

G1从整体上来看,采用基于“标记-整理”算法实现收集器

G1从区域性上来看,采用基于“复制”算法实现。

④可预测停顿

使用G1收集器时,Java堆内存布局与其他收集器有很大差别,它将整个Java堆划分成为多个大小相等的独立区域。

G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region。

自己是从事了七年开发的Android工程师,不少人私下问我,2019年Android进阶该怎么学,方法有没有?

没错,年初我花了一个多月的时间整理出来的学习资料,希望能帮助那些想进阶提升Android开发,却又不知道怎么进阶学习的朋友。【包括高阶UI、效能优化、架构师课程、NDK、Kotlin、混合式开发(ReactNative+Weex)、Flutter等架构技术资料】,希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。

资料获取方式:转发+关注后私信回复我【学习】免费获取Android进阶开发资料!!!

资料大全

文章标签: 报价宝 降噪耳机价格 耳机价格 红米手机价格 华为手机价格 小米手机价格 电视机价格 笔记本电脑价格 笔记本价格 汽车价格 数码相机价格 手机价格 笔记本价格 小米手机价格 红米手机价格