3.3、JVM-垃圾回收-如何回收?垃圾收集器

导读:本篇文章讲解 3.3、JVM-垃圾回收-如何回收?垃圾收集器,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

目录

Serial收集器

ParNew收集器

Parallel Scavenge收集器

CMS收集器

G1收集器


  • 如何判断对象为垃圾对象?

    • 引用计数法

    • 可达性分析法

  • 如何回收?

    • 回收策略

      • 标记-清除算法

      • 复制算法

      • 标记-整理算法

      • 分代收集算法

    • 垃圾收集器

      • Serial

      • Parnew

      • Parallel Scavenge

      • CMS

      • G1

  • 何时回收?


  • 并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程任然处于等待状态。

  • 并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户程序在继续运行,而垃圾收集程序运行于另一个CPU上。


Serial收集器

    serial收集器是最基本、发展历史最悠久的收集器,曾经(在JDK1.3.1之前)是虚拟机新生代收集的唯一选择。这个收集器是一个单线程的收集器,但它的“单线程”的意义并不仅仅说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是它在进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。

    “Stop The World”这个名字也许听起来很酷,但这项工作实际上是由虚拟机在后台自动发起和自动完成的,在用户不可见的情况下把用户正常工作的线程全部停掉,这对很多应用来说都是难以接受的。试想一下,要是你的计算机每运行一个小时就会暂停响应5分钟,这会是什么样的体验?所以其他的收集器都是为了解决这一问题(线程因内存回收而导致的停顿)做出的改进。

3.3、JVM-垃圾回收-如何回收?垃圾收集器


ParNew收集器

ParNew收集器其实就是Serial收集器的多线程版本,除了使用多线程进行垃圾收集之外,其余行为包括Serial收集器可用的所有控制参数、收集算法、Stop The World、对象分配规则、回收策略等都与Serial收集器完全一样。

3.3、JVM-垃圾回收-如何回收?垃圾收集器


Parallel Scavenge收集器

Parallel Scavenge收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集器。。。看上去和ParNew都一样,那它有什么特别之处呢?

Parallel Scavenge收集器的特点是它的关注点与其他的收集器不同,CMS等收集器的关注点是尽可能的缩短垃圾收集时用户线程的停顿时间,而Paralle Scavenge收集器的目标则是达到一个可控制的吞吐量(Throughput)。所谓的吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量=运行用户代码的时间/(运行用户代码的时间+垃圾收集时间),虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%。

  • JVM参数

    • -XX:MaxGCPauseMillis:控制最大垃圾收集停顿时间,单位毫秒。

      • MaxGCPauseMillis参数的值是一个大于0的毫秒数,收集器将尽可能的保证内存回收花费的时间不超过设定值。注意不要认为如果把这个参数的值设置的稍小一点就能使得系统的垃圾收集变得更快,GC停顿时间缩短是以牺牲吞吐量和新生代空间来换取的。举例:收集200MB新生代肯定比手机500MB快,会导致垃圾收集的频率更频繁,原来10秒收集一次、每次停顿100毫秒,现在变成5秒收集一次、每次停顿70毫秒。停顿时间确实下降了,但吞吐量也下降了。

    • -XX:GCTimeRatio:直接设置吞吐量大小。

      • GCTimeRatio参数的值应当是一个大于0且小于100的整数,也就是垃圾收集时间占总时间的比率,相当于是吞吐量的倒数。如果把此参数设置为19,那允许的最大GC时间就占总时间的5%(1/(1+19)),默认值为99,就是允许最大1%(1/(1+99))的垃圾收集时间。


CMS收集器

    CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。如前很大一部分的应用在Java的B/S系统服务上。这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求。

    CMS收集器是基于“标记-清除”算法(此算法用在老年代中,所以CMS收集器也是老年代收集器)实现的,它的运作过程相对于前面几种收集器来说更复杂。整个过程分为4个步骤。

CMS收集器执行步骤:

  • 初始标记(CMS initial mark)

  • 并发标记(CMS concurrent mark)

  • 重新标记(CMS remark)

  • 并发清除(CMS concurrent sweep)

3.3、JVM-垃圾回收-如何回收?垃圾收集器

CMS收集器的优点:

  • 并发收集

  • 低停顿

CMS收集器的缺点:

  • CPU资源敏感

  • 浮动垃圾

    • 浮动垃圾是无法在当次收集中处理掉留待下一次GC时再清理掉。这以部分垃圾就称为“浮动垃圾”,也是由于在垃圾收集阶段用户线程还需要运行,那就还需要预留足够的内存空间给用户线程使用,因此CMS收集器不能像其他收集器那样等到老年代几乎完全被填满了再进行收集,需要预留一部分空间提供并发收集时的程序运作使用。JDK1.5默认CMS收集器当老年代使用了68%的空间后会被激活,可以通过-XX:CMSInitiatingOccupancyFraction的值来提高触发百分比,JDK1.6中CMS收集器的启动阀值提升为98%,所以不建议使用-XX:CMSInitiatingOccupancyFraction,不然设置的太高可能会导致“Concurrent Mode Failure”失败,导致性能下降。

  • 空间碎片

    • 因为CMS使用的是“标记-清除”算法实现的收集器。收集结束时会有大量空间碎片产生。空间碎片过多时,将会导致大对象分配时老年代还有很大的空间剩余,但是无法找到足够大的连续空间来分配该对象,不得不提前触发一次Full GC。为了解决这个问题,CMS收集器提供了-XX:+UseCMSCompactAtFullCollection开关参数(默认开启),用于在CMS收集器顶不住要进行Full GC是开启内存碎片的合并整理过程。内存整理的过程是无法并发的,空间碎片问题没有了,但停顿时间不得不变长。所以又有另外一个参数-XX:CMSFullGCsBeforeCompaction来设置执行多少次不压缩的Full GC后,跟着来一次带压缩的(默认值为0,表示每次进入Full GC时都会进行碎片整理)。


G1收集器

G1收集器面向服务端应用的垃圾收集器。在G1之前的其他收集器进行垃圾收集的范围都是整个新生代或者老年代,而G1不再是这样。使用G1收集器时,Java堆内存布局就与其他收集器有很多差别。它将整个Java堆划分为多个大小相同的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region(不需要连续)的集合。

特点:

  • 并行与并发

    • G1充分利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短停顿的时间,部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让Java程序继续执行。

  • 分代收集

  • 空间整合

    • CMS采用的是“标记-清除”算法,而G1从整体上看基于“标记-整理”算法实现的收集器。而从两个Region(范围)之间上来看是基于“复制”算法实现的,所以G1使用了“标记-整理”和“复制”两种算法来实现。这两种算法在G1中的应用意味着G1运作期间不会产生内存空间碎片,收集后能提供规整的可用内存。这种特性有利于程序长时间运行,分配大对象时不会因为无法找到连续的内存空间而提前触发下一次GC。

  • 可预测停顿

    • 让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。

问题:

  • Region不可能是孤立的,一个对象分配在某个Region中,它并非只能被本Region中的其他对象引用,而是可以与整个Java堆任意的对象发生引用关系。那在做可达性判断确定对象是否存活的时候,岂不是要扫描整个Java堆彩宁保证准确性?

    • G1中每个Region都有一个与之对应的Remembered Set,虚拟机发现程序在对Reference引用类型的数据进行写操作时,会产生一个Write Barrier暂时中断写操作,检查引用的对象是否处于不同的Region之中,如果是,便通过CardTable把相关引用信息记录到被引用对象所属Region的Remembered Set之中。当进行内存回收时,在GC根节点的枚举范围中加入Remembered Set即可保证不对全堆扫描也不会有垃圾内存遗漏。

步骤:

  • 初始标记

  • 并发标记

  • 最终标记

  • 筛选回收

 3.3、JVM-垃圾回收-如何回收?垃圾收集器

 

 

 

 

 

 

 

 

                                                                                                 注:博文内容来自书本《深入理解Java虚拟机》第2版 周志明著

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/72575.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!