前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >GC回收算法&GC回收器

GC回收算法&GC回收器

作者头像
Noneplus
发布2020-08-11 10:20:41
8790
发布2020-08-11 10:20:41
举报
文章被收录于专栏:开发笔记开发笔记

垃圾标记

在回收垃圾前,需要判断哪些是垃圾,哪些不是。

引用计数法

原理:被引用+1,未被引用-1,为0时回收。

问题:无法解决循环引用的问题

  • 什么是循环引用?(环) A 引用了 B,B 引用了 C,C 引用了 A,它们各自的引用计数都为 1。但是它们三个对象却从未被其他对象引用,(假设有1000个对象时,这三个就是垃圾;如果只有4个对象,那么另外一个就是垃圾)只有它们自身互相引用。从垃圾的判断思想来看,它们三个确实是不被其他对象引用的,但是此时它们的引用计数却不为零。

可达性分析(主流使用)

通过GC Roots作为起点遍历,判断是否被引用。

GC Roots包括:

  • 虚拟机栈中引用的对象
  • 方法区静态属性引用的对象
  • 方法区常量引用的对象
  • JNI引用的对象(Native方法)

【引用的判定】

  • 强引用:抛异常也不回收
  • 软引用:内存空间不够就回收
  • 弱引用:发现了就回收(按线程优先级)
  • 虚引用:任何时刻都会被回收

GC回收算法

分代收集本质上就是分类讨论,根据对存活对象的预判,采用效率更高的收集算法。

标记-清除算法(适合老年代)

先通过GC Roots遍历,标记不可达对象,而后清除。

问题:产生不连续的空间碎片

标记-复制算法(适合年轻代)

折半内存,将存活对象复制到另一半内存中,然后把当前内存全部回收。

问题:解决了空间碎片,但只能使用一半的内存

标记-整理算法(适合老年代)

将存活对象移动到内存的一端,然后清除边界之外的所有内存。

【既不会产生空间碎片,也不会导致内存折半】

“因地制宜”——分代算法

分代算法,就是根据 JVM 内存的不同内存区域,采用不同的垃圾回收算法。

例如对于存活对象少的新生代区域,比较适合采用复制算法。这样只需要复制少量对象,便可完成垃圾回收,并且还不会有内存碎片。

而对于老年代这种存活对象多的区域,比较适合采用标记清除算法或标记整理算法,这样不需要移动太多的内存对象。

GC回收器

Serial 回收器

Serial回收器是一种单线程串行回收器,使用复制算法,在执行回收时会产生较长时间的停顿,优点是不会产生线程切换的开销

通过JVM参数-XX:+UseSerialGC可以使用串行垃圾回收器。

Serial Old 回收器

SO回收器是一种多线程并行回收器,使用标记整理算法,适用老年代

ParNew回收器

PN回收器是一种多线程并行器,使用复制算法。

参数控制:-XX:+UseParNewGC

Parallel Old回收器

PO是一种多线程回收器,使用标记整理算法,适用老年代

Parallel Scavenge回收器

PS回收器也是一种多线程并行回收器,使用复制算法,特点是可设置吞吐量

参数:-XX:+UseParallelGC

CMS收集器

CMS使用标记清除算法,主要目的是回收时的低停顿。

过程:

  • 初始标记:单线程(触发停顿),标记与GC Roots关联的对象
  • 并发标记:标记不可达对象(可能产生回收对象,所以之后需要重新标记)
  • 重新标记:单线程(触发停顿),纠正标记
  • 并发清除:清除对象

问题:

  • CPU资源消耗高
  • 浮动垃圾产生(回收时产生了新的垃圾)
  • 标记清除算法导致的空间碎片问题

G1回收器

特点:

  • 停顿时间:G1可充分利用多核多CPU的优势减少停顿时间,并且可建立可以预测的停顿模型,可设置停顿的时间
  • 支持分代回收,可使用分区策略同时兼顾老年代和年轻代
  • 使用标记整理算法,不会产生空间碎片

分区思路:

为什么使用分区:针对老年代的操作需要扫描所有的老年代空间;由于连续,必须分配年轻代和老年代的地址位置

G1之前的内存都是连续的:

image-20200730155606019
image-20200730155606019

G1回收器的内存按区等分,分为eden,survivor,old和humongous:

image-20200730155714112
image-20200730155714112

G1回收器回收流程:

  • 初始标记
  • 并发标记
  • 重新标记
  • 并发回收

Minor GC 和Full GC

从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC。当 JVM 无法为一个新的对象分配空间时会触发 Minor GC,比如当 Eden 区满了。

Full GC 是清理整个堆空间—包括年轻代和永久代。

Full GC执行条件:

  • 调用System.gc时,系统建议执行Full GC,但是不必然执行
  • 老年代空间不足
  • 方法区空间不足
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-08-05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 垃圾标记
  • 引用计数法
  • 可达性分析(主流使用)
  • GC回收算法
    • 标记-清除算法(适合老年代)
      • 标记-复制算法(适合年轻代)
        • 标记-整理算法(适合老年代)
          • “因地制宜”——分代算法
          • GC回收器
            • Serial 回收器
              • Serial Old 回收器
                • ParNew回收器
                  • Parallel Old回收器
                    • Parallel Scavenge回收器
                      • CMS收集器
                        • G1回收器
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档