jvm05-垃圾回收器

Posted fuzy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jvm05-垃圾回收器相关的知识,希望对你有一定的参考价值。

垃圾收集算法

标记-清除

找出内存中需要回收的对象,并且把他们标记出来;此时堆中所有的对象都会被扫描一遍,从而确定需要回收的对象,比较耗时。另外此算法会产生大量的空间碎片。

  • 标记阶段

    image-20210130142513882
  • 清除阶段

    【jvm】05-垃圾回收器
    image-20210130142543198

标记-复制

将内存划分为两块相等的区域,每次只使用其中的一块。但该算法比较消耗空间。

  • 标记阶段

    【jvm】05-垃圾回收器
    image-20210130142954421
  • 复制阶段

    如下图,将所有存活对象移到右边,同时回收左边的垃圾。

    【jvm】05-垃圾回收器
    image-20210130143019975

标记-整理

区别于标记复制算法,标记-整理算法是先标记存活对象,然后将所有存活对象移动到一块连续区域,然后清理掉存活区域边界以外的内存。

  • 标记阶段

    【jvm】05-垃圾回收器
    image-20210130143543684
  • 整理阶段

    【jvm】05-垃圾回收器
    image-20210130143604760

分代收集

针对堆中不同区域,制定不同算法。

Young区:对象特点大多数都是朝生夕死,复制算法效率高。

Old区:该区域都是存活时间比较长的对象,一般发生垃圾回收的频率相对来说较低;所以采取标记清除或者标记整理算法。

垃圾收集器

如果说垃圾收集算法是内存回收的策略,那么垃圾收集器就是内存回收的具体实现。

【jvm】05-垃圾回收器
image-20210130145040032

如上图展示了堆内存中不同区域可使用的垃圾收集器策略。

  • Young区:Serial、ParNew、Parallel Scavenge

  • Old区:CMS、Serial Old、Parallel Old

  • G1既能在老年代中被使用也能在新生代中被使用。

`Serial`收集器

它是一种单线程收集器,不仅仅意味着它只会使用一个CPU或者一条收集线程去完成垃圾收集工作,更 重要的是其在进行垃圾收集的时候需要暂停其他线程。

  • 优点:简单高效,拥有很高的单线程收集效率

  • 缺点:收集过程需要暂停所有线程

  • 算法:新生代中复制算法;老年代中使用标记整理算法

  • 适用范围:堆

  • 应用:Client模式下的默认新生代收集器

【jvm】05-垃圾回收器
image-20210130150053236

`ParNew`收集器

可以把这个收集器理解为Serial收集器的多线程版本。

  • 优点:在多CPU时,比Serial效率高。

  • 缺点:收集过程暂停所有应用程序线程,单CPU时比Serial效率差。

  • 算法:复制算法

  • 适用范围:新生代

  • 应用:运行在Server模式下的虚拟机中首选的新生代收集器

【jvm】05-垃圾回收器
image-20210130145921347

`Parallel Scavenge`与`Parallel Old`收集器

Parallel Scavenge收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集 器,看上去和ParNew一样,但是Parallel Scanvenge更关注系统的吞吐量。

Parallel Old是老年代的收集器。使用多线程和标记-整理算法进行垃圾回 收,也是更加关注系统的吞吐量。

吞吐量=运行用户代码的时间/(运行用户代码的时间+垃圾收集时间)

比如虚拟机总共运行了100分钟,垃圾收集时间用了1分钟,吞吐量=(100-1)/100=99%。

若吞吐量越大,意味着垃圾收集的时间越短,则用户代码可以充分利用CPU资源,尽快完成程序 的运算任务。

-XX:MaxGCPauseMillis控制最大的垃圾收集停顿时间,
-XX:GCTimeRatio直接设置吞吐量的大小。

`CMS`收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取 最短回收停顿时间 为目标的收集器。采用的是"标记-清除算法",整个过程分为4步

(1)初始标记 CMS initial mark 标记GC Roots直接关联对象,不用Tracing,速度很快
(2)并发标记 CMS concurrent mark 进行GC Roots Tracing(找出存活对象,所有GC Root链上的都为存活对象)
(3)重新标记 CMS remark 修改并发标记因用户程序变动的内容
(4)并发清除 CMS concurrent sweep 清除不可达对象回收空间,同时有新垃圾产生,留着下次清理称为浮动垃圾
 

由于整个过程中,并发标记和并发清除,收集器线程可以与用户线程一起工作,所以总体上来 说,CMS收集器的内存回收过程是与用户线程一起并行地执行的。

优点:并发收集、停顿低

缺点:产生大量碎片,降低系统吞吐量

【jvm】05-垃圾回收器
image-20210130183843813

`G1(Garbage-First)`

使用G1收集器时,Java堆的内存布局与就与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再 是物理隔离的了,它们都是一部分Region(不需要连续)的集合。所谓的G1就是优先回收垃圾最多的Region区域。

值得注意的是每个Region大小都是一样的,可以是1M到32M之间的数值,但是必须保证是2的n次幂;如果对象太大,一个Region放不下[超过Region大小的50%],那么就会直接放到H中。

image-20210130185724499

G1的工作流程如下:

(1)初始标记(Initial Marking) 标记以下GC Roots能够关联的对象,并且修改TAMS的值,需要暂停用户线程
(2)并发标记(Concurrent Marking) 从GC Roots进行可达性分析,找出存活的对象,与用户线程并发执行
(3)最终标记(Final Marking) 修正在并发标记阶段因为用户程序的并发执行导致变动的数据,需暂停用户线程
(4)筛选回收(Live Data Counting and Evacuation) 对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间制定回收计划
image-20210130190140097

G1垃圾回收流程

`ZGC`收集器

JDK11新引入的ZGC收集器,不管是物理上还是逻辑上,ZGC中已经不存在新老年代的概念了 会分为一个个page,当进行GC操作时会对page进行压缩,因此没有碎片问题只能在64位的linux上使用,目前用得还比较少。

优点:

(1)可以达到10ms以内的停顿时间要求

(2)支持TB级别的内存

(3)堆内存变大后停顿时间还是在10ms以内

常见问题

  • 如何选择垃圾回收器

    优先调整堆的大小让服务器自己来选择
    如果内存小于100 M ,使用串行收集器
    如果是单核,并且没有停顿时间要求,使用串行或 JVM 自己选
    如果允许停顿时间超过1秒,选择并行或 JVM 自己选
    如果响应时间最重要,并且不能超过1秒,使用并发收集器
  • 如何开启需要的垃圾回收器

    (1)串行
    -XX:+UseSerialGC
    -XX:+UseSerialOldGC
    (2)并行(吞吐量优先):
    -XX:+UseParallelGC
    -XX:+UseParallelOldGC
    (3)并发收集器(响应时间优先)
    -XX:+UseConcMarkSweepGC
    -XX:+UseG1GC


以上是关于jvm05-垃圾回收器的主要内容,如果未能解决你的问题,请参考以下文章

python垃圾回收机制

一文读懂Python垃圾回收机制收藏版

一文读懂Python垃圾回收机制收藏版

一文读懂Python垃圾回收机制收藏版

一文读懂Python垃圾回收机制收藏版

一文读懂Python垃圾回收机制收藏版