java虚拟机四:垃圾回收算法与垃圾收集器

fengweiweicoder fengweiweicoder     2022-12-05     683

关键词:

  在Java运行时的几个数据区域中,程序计数器,虚拟机栈,本地方法栈3个区域随着线程而生,随线程而灭,因此这几个区域的内存分配和回收具有确定性,不需要过多考虑垃圾回收问题,因为方法结束或者线程结束时,内存就回收了。但是方法区和堆区不一样,一个接口或者实现类所需要的内存可能不一样,一个方法的多个分支需要的内存也可能不一样,只有程序运行时才能知道创建哪些对象,这部分内存的分配和回收是动态的。

  在进行垃圾回收时候,首先需要判断哪些对象需要回收,这就涉及到回收算法的问题。

一、垃圾回收算法

1.标记-清除算法

  标记-清除算法是一种最基础的垃圾收集算法,分为“标记”和“清除”两步。“标记”阶段标记所有需要进行垃圾回收的对象,标记完成后统一回收被标记的对象。这种算法的不足点在于:

  (1)效率问题,标记和清除两个过程效率都不高;

  (2)空间问题,标记清除后会产生大量不连续碎片,后续如果需要为较大对象分配空间,则又需触发垃圾回收。

2.复制算法

  为了解决标记-清除算法的效率问题,出现了复制算法。这种算法把内存按照容量划分为大小相同的两块,每次只是用其中一块,当这块内存用完了,就把还存活的对象复制到另外一块中,并将这块的内存清理掉,然后使用另外一块,当另外一块内存用完了,再把存活的对象复制到这块中,并清理另外一块内存,依次类推。

  复制算法主要用于新生代的回收,在HotSpot虚拟机中,新生代内存划分为一块较大的Eden空间,和两块较小的Survivor空间,每次使用Eden空间和其中一块Survivor空间。当进行垃圾回收时,会把Eden空间和Survivor空间中存活的对象一次性复制到另外一块Survivor空间上,最后清理掉Eden空间和刚才使用过的Survivor空间。HotSpot虚拟机中,默认情况下Eden空间和Survivor空间的大小比例是8:1,即Eden空间占整个新生代的80%,每次新生代中使用的空间为80%+10%=90%,闲置空间10%。

3.标记-整理算法

  复制算法适用于那种对象存活率较低的场景,在对象存活率较高时,使用复制收集算法意味着需要进行大量复制,会使效率降低,同时复制大量存活对象到另外一块内存,意味着需要有足够大的内存来保存这些对象,这势必会降低内存使用率。根据老年代的特点,有人提出标记-整理算法,和标记-清除算法不同的是,标记整理算法将存活的对象向一端移动,然后直接清理掉端边界之外的内存。

4.分代收集算法

  目前商业虚拟机中都使用分代收集算法。一般将Java堆分为新生代和老年代,新生代进行垃圾收集发现有大量对象死去,只有少量对象存活,那么就使用复制算法。老年代中对象存活率较高,使用标记-清除算法或者标记-整理算法。

二、垃圾收集器

   垃圾收集算法提供了内存回收的方法论,垃圾收集器是内存回收的方法论。每个厂商对垃圾收集器的实现不一样,这里主要讨论Jdk1.7 Update 14之后的HotSpot虚拟机。这个虚拟机中包含的垃圾收集器有如下7种:

                                     技术图片

    以上收集器之间如果有连线,则表明可以搭配使用,虚拟机所处区域,表示他是新生代收集器还是老年代收集器。

1.Serial收集器

  Serial收集器是一种最基本的单线程收集器,这种收集器工作时,必须停止其他所有工作线程,优点在于简单高效,但体验很不友好,目前主要应用场合是:虚拟机运行在Client模式下的默认新生代收集。器。

2.ParNew收集器

  parNew收集器是Serial收集器的多线程版本,常用参数设置:

   -XX:+UseConcMarkSweepGC :设置ParNew为默认的新生代收集器;

   -XX:+UseParNewGC :指定使用ParNew为年轻代收集器,强制指定;

   -XX:ParallelGCThreads=n :设置收集器的线程数为n。

3.Parallel Scavenge收集器

  Parallel Scavenge收集器是一个使用复制算法的新生代收集器,这种收集器的主要目标是达到一个可控制的吞吐量(Throughput,CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间))。由于与吞吐量关系密切,故而Parallel Scavenge收集器也称为“吞吐量优先”收集器。常用参数设置:

   -XX:MaxGCPauseMillis=n :设置年轻代垃圾收集的最长时间;

   -XX:GCTimeRatio=n :设置垃圾收集总可用时长的比例,和吞吐量直接相关;

   -XX:+UseAdaptiveSizePolicy 自适应大小开关,配置该选项之后,每次GC后会重新计算 Eden、From 和 To 区的大小,计算依据是 GC 过程中统计的 GC 时间、吞吐量、内存占用量,因此设置此参数之后就不需要再设置 -XX:SurvivorRatio 、 -XX:PretenureSizeThreshold 等参数了。

4.Serial Old收集器

  Serial收集器的老年版本,也是一个单线程收集器,使用的是“标记-整理”算法,这种收集器的主要意义也是给Client模式下的虚拟机使用。

5.Parallel Old收集器

  Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge收集器和Parallel Old收集器的组合。

6.CMS收集器

  CMS收集器是一种以获取最短回收停顿时间为目标的收集器。它基于“标记-清除”算法实现,运作过程相对于其他几种收集器更复杂一些。分为以下四个过程:

  (1)初始标记(CMS initial mark):标记一下CG Roots能关联到的对象;

  (2)并发标记(CMS concurrent mark):进行CG Roots Tracing的过程;

  (3)重新标记(CMS remark):修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。

  (4)并发清理(CMS concurrent sweep)

  CMS 收集器的优点在于并发收集,低停顿。其缺点在于以下三点:

  (1)CMS收集器对CPU很敏感,CMS默认回收线程是(CPU数量+3)/4,当CPU在4个以上时,并发收集时垃圾收集线程不少于25%的CPU资源,并随着CPU数量增加而下降。但是当CPU不足4个时,CMS对用户程序的影响就会变得很大。

  (2)CMS收集器无法处理浮动垃圾。由于CMS收集器并发清理阶段用户线程还在运行着,伴随着程序运行就会有垃圾产生,这部分垃圾在标记过后,CMS收集器无法在当次收集中清理这些垃圾。

  (3)由于CMS收集器是一种基于“标记-清除”算法的收集器,这种算法实现的收集器在收集结束后会有大量不连续碎片产生。碎片过多时会给大对象分配带来很大麻烦,往往老年代还有很大空间剩余,但是无法找到连续空间分配当前对象,因而不得不提前触发Full GC。

7.G1收集器

  G1收集器是一款面向服务端应用的垃圾收集器,与其他收集器相比,G1收集器具有如下优点:

  (1)并发与并行:G1能充分利用多CPU,多核硬件优势,使用多个CPU来减少停顿时间;

  (2)分代收集:G1不需要其他收集器配合就能独立管理整个堆的垃圾收集,且它能采用不同方式去处理新建对象和已经存活了一段时间,熬过多次GC的旧对象以获得更好的收集效果。

  (3)空间整合:使用G1收集器不会产生内存碎片,收集后能提供规整的可用内存。这种特性有利于程序长时间运行,分配大对象时候不会因为无法找到连续内存空间而提前触发下一次GC.

  (4)可预测的停顿:G1除了追求低停顿,还能建立可预测的停顿时间模型,能让使用着指定在长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不超过N毫秒。

 

三、垃圾收集参数总结

参数描述
UseSerialGC

虚拟机运行在Client模式下的默认值,打开此开关后,使用Serial+Serial Old的收集器组合进行内存回收

UseParNewGC 打开此开关后,使用ParNew + Serial Old 的收集器组合进行内存回收
UseConcMarkSweepGC 打开此开关后,使用ParNew + CMS + Serial Old 的收集器组合进行内存回收。Serial Old 收集器将作为CMS收集器出现Concurrent Mode Failure失败后的后备收集器使用
UseParallelGC 虚拟机运行在Server 模式下的默认值,打开此开关后,使用Parallel Scavenge + Serial Old(PS MarkSweep)的收集器组合进行内存回收
UseParallelOldGC 打开此开关后,使用Parallel Scavenge + Parallel Old 的收集器组合进行内存回收
SurvivorRatio 新生代中Eden 区域与Survivor 区域的容量比值,默认为8,代表Eden :Survivor=8∶1
PretenureSizeThreshold 直接晋升到老年代的对象大小,设置这个参数后,大于这个参数的对象将直接在老年代分配
MaxTenuringThreshold 晋升到老年代的对象年龄。每个对象在坚持过一次Minor GC 之后,年龄就加1,当超过这个参数值时就进入老年代
UseAdaptiveSizePolicy 动态调整Java 堆中各个区域的大小以及进入老年代的年龄
HandlePromotionFailure 是否允许分配担保失败,即老年代的剩余空间不足以应付新生代的整个Eden 和Survivor 区的所有对象都存活的极端情况
ParallelGCThreads 设置并行GC 时进行内存回收的线程数
GCTimeRatio GC 时间占总时间的比率,默认值为99,即允许1% 的GC 时间。仅在使用Parallel Scavenge 收集器时生效
MaxGCPauseMillis 设置GC 的最大停顿时间。仅在使用Parallel Scavenge 收集器时生效
CMSInitiatingOccupancyFraction 设置CMS 收集器在老年代空间被使用多少后触发垃圾收集。默认值为68%,仅在使用CMS 收集器时生效
UseCMSCompactAtFullCollection 设置CMS 收集器在完成垃圾收集后是否要进行一次内存碎片整理。仅在使用CMS 收集器时生效
CMSFullGCsBeforeCompaction 设置CMS 收集器在进行若干次垃圾收集后再启动一次内存碎片整理,仅在使用CMS 收集器时生效

 

 

参考资料:《深入理解Java虚拟机 JVM高级特性与最佳实践 第2版》

深入理解java虚拟机gc垃圾回收-垃圾收集算法

文章目录前言一、分代收集理论二、标记-清除算法三、标记-复制算法四、标记-整理算法结尾前言从如何判定对象消亡的角度出发,垃圾收集算法可以划分为“引用计数式垃圾收集”(ReferenceCountingGC)和“追踪式垃... 查看详情

深入理解java虚拟机gc垃圾回收-经典垃圾收集器

文章目录前言一、Serial收集器(标记-复制算法)二、ParNew收集器(标记-复制算法)三、ParallelScavenge收集器(标记-复制算法)四、SerialOld收集器(标记-整理算法)五、ParallelOld收集器(标记-整理算法)六、CMS收集器(标记-清除算法)七、GarbageFi... 查看详情

java虚拟机垃圾收集器与内存分配策略

Java虚拟机垃圾收集器与内存分配策略概述那些内存须要回收,什么时候回收。怎样回收是GC须要完毕的3件事情。程序计数器。虚拟机栈与本地方法栈这三个区域都是线程私有的,内存的分配与回收都具有确定性,内存随着方法... 查看详情

java虚拟机垃圾收集器分析基本回收算法垃圾回收器(代码片段)

java虚拟机垃圾收集器分析1、活动对象追踪root对象算法:深度追踪root对象,将heap中所有被引用到的root做标志,所有未被标志的对象视为非活动对象,所占用的空间视为非活动内存。2、常用算法Copy算法1方法:... 查看详情

垃圾收集器与内存分配策略(深入理解java虚拟机)

3.1 概述垃圾收集器要解决哪些问题?哪些内存需要回收什么时候回收如何回收引用计数算法:当有一个地方引用,+1,引用失效,-1。   缺点:对象之间相互循环引用的问题。可达性分析算法:思路:通过一系列... 查看详情

jvm垃圾回收2(垃圾收集算法)

...、关于几个概念:(标记垃圾算法、垃圾收集算法、垃圾收集器)  前面说了如何寻找jvm垃圾,有两种方法:引用计数法/可达性算法。这篇准备讲,标记完垃圾之后,回收的算法,这里的算法只是垃圾回收的思想。后面会讲... 查看详情

java垃圾收集与内存回收

...能到达的对象为可用,否则为不可用。GCRoots对象包括:虚拟机栈(栈帧中的本地变量表)中引用的对象方法区中类 查看详情

jvm垃圾回收-7种垃圾收集器

概述垃圾收集器是垃圾回收算法(标记-清除算法、复制算法、标记-整理算法)的具体实现,不同商家、不同版本的JVM所提供的垃圾收集器可能会有很在差别,本文主要介绍HotSpot虚拟机中的垃圾收集器。7种垃圾收集器如图所示... 查看详情

jvm之垃圾收集算法与垃圾收集器(代码片段)

Java垃圾收集算法与垃圾收集器1.垃圾收集的经典四连问1.1.什么是垃圾?1.2.为什么要垃圾回收?1.3.垃圾什么时候回收?1.4.垃圾如何回收?2.垃圾回收的相关概念2.1System.gc()的理解2.2内存溢出与内存泄漏2.3StopTheWorld2.4垃圾... 查看详情

jvm垃圾回收算法与垃圾收集器

【JVM】垃圾回收算法与垃圾收集器【JVM】垃圾收集器 查看详情

《深入理解java虚拟机》读后笔记-垃圾收集算法

文章目录《深入理解Java虚拟机》读后笔记-垃圾收集算法1.概述2.如何判断对象已死?2.1引用计数算法2.2可达性分析算法2.3Java中的引用2.4回收方法区3.垃圾收集算法3.1分代收集理论3.2标记-清除算法3.3标记-复制算法3.4标记-整理... 查看详情

java垃圾是怎么回收的,回收算法

...是加大了程序的负担,有可能影响程序的性能。1.垃圾收集器的主要功能有(1)定期发现那些对象不再被引用,并把这些对象占据的堆空间释放出来。(2)类似于操作系统的内存管理,垃圾收集器还需要处理由于对象动态生成... 查看详情

垃圾收集与几种常用的垃圾收集算法

...到了Java内存运行时区域的各个部分,其中程序计数器、虚拟机栈、本地方法栈3个区域会随着线程而生,随线程而灭;栈中的栈帧随着方法的进行有条不紊地执行着出栈和入栈操作。每一个栈帧中分配多少内存基本上是在类结构... 查看详情

垃圾回收器

HotSpot虚拟机中有7种垃圾收集器:Serial、ParNew、ParallelScavenge、SerialOld、ParallelOld、CMS、G1。垃圾收集器是垃圾回收算法(标记-清除算法、复制算法、标记-整理算法、分代收集)的具体实现,不同商家、不同版本的JVM所提供的垃圾... 查看详情

《深入理解java虚拟机》jdk的垃圾收集算法

...入理解JAVA虚拟机》一书中讲到JVM的垃圾收集算法和垃圾收集器。 垃圾收集算法分为:1、标记清除算法通常用在回收老年代内存。最早的搜集算法就是标记清除(Mark-Sweep)算法了。其原理是分为标记和清除两个阶段:首先标... 查看详情

如何修改jvm虚拟机垃圾回收器

参考技术A垃圾收集器是垃圾回收算法(标记-清除算法、复制算法、标记-整理算法、火车算法)的具体实现,不同商家、不同版本的JVM所提供的垃圾收集器可能会有很在差别,本文主要介绍HotSpot虚拟机中的垃圾收集器。本回答... 查看详情

java垃圾回收算法和垃圾收集器

java垃圾回收算法以及原理在java中常见的垃圾回收算法有四种,分别是标记清除算法、复制算法、标记整理算法以及分代回收算法。标记清除算法(Mark-Sweep算法)标记清除算法是最基础的垃圾回收算法,容易实现,而且思想也很... 查看详情

jvm垃圾回收算法与垃圾收集器(代码片段)

垃圾回收算法与垃圾收集器1.垃圾收集算法1.1标记清除算法1.1.1基本概念1.1.1.1`mutator`和`collector`1.1.1.2`mutatorroots`(`mutator`根对象)1.1.1.3可达对象1.1.2垃圾回收过程1.1.2.1标记(mark)1.1.2.2清除(sweep)1.1.2.3整体流程1.1 查看详情