Java垃圾回收机制

概述

垃圾回收机制是Java语言一个非常重要的特性。通过该机制程序员不用手动去管理内存,大大提高了开发效率,也可以有效避免人为的疏忽造成内存泄露。通过对Java内存模型的了解,我们知道Java的对象实例基本都存储在Java堆中,由于很多对象只有在运行期才能确定是否需要创建,使得该区域的内存需要进行动态分配和回收,以提高内存的使用效率,所以垃圾收集器主要关注的就是该区域的内存。而程序计数器、虚拟机栈、本地方法栈都是线程独占的,它们会跟随线程的创建而创建,线程的销毁而销毁,因此这几个区域的内存分配和回收都具备确定性,不需要过多的考虑内存回收问题。

垃圾回收算法

在这里插入图片描述

标记算法

1. 引用计数算法
该算法的实现是给对象添加一个引用计数器,每当有一个地方引用它时,计数器数值就加1;当引用失效时,计数器值就减1;当计数器数值为0时表示该对象不可再被使用,则可以对其进行回收。
优点: 实现简单,判定效率高。
缺点: 很难解决对象循环引用问题。

2. 可达性分析算法(根搜索算法)
该算法是从离散数学中的图论引入的,程序将所有引用关系看成是一张图,通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来讲,就是从GC Roots到这个对象不可达)时,则说明该对象是不可用的。
Java中可以作为GC Roots的对象

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象。
  • 方法区中类静态属性引用的对象。
  • 方法区中常量引用的对象。
  • 本地方法栈中JNI(Native方法)引用的对象。
    在这里插入图片描述
回收算法

1. 标记-清除算法
标记-清除算法分为标记和清除两个阶段,首先从根集合进行扫描,对存货的对象进行标记,然后对堆内存从头到尾进行线性遍历,回收不可达对象的内存。
缺点:

  • 效率问题,标记和清除两个过程的效率都不高。
  • 空间问题,内存碎片化严重。

2. 复制算法
复制算法的原理是将可用内存按容量划分为大小相等的两块(对象面和空闲面),每次只使用其中的一块,当这一块的内存用完了,就将还存活的对象复制到另一块上,然后再把已使用过的内存空间一次清理掉。
优点:

  • 解决了内存碎片化问题。
  • 按顺序分配内存,简单高效。
  • 适用于对象存活率低的场景(如:新生代)。

缺点:

  • 将内存缩小为原来的一半。
  • 在对象存活率较高的场景下需要进行较多的复制操作,效率会变低。

3. 标记-整理算法
标记-整理算法的标记过程与标记-清除算法一致,先从根集合进行扫描,对存活的对象进行标记,但是后续步骤不是直接对可回收的对象进行清理,而是移动所有存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收。
优点: 解决了内存碎片化问题,不用设置两块内存互换。
缺点: 比标记-清除算法增加了对象移动的过程,所以实现成本更高。适用于对象存活率高的场景(如:老年代)。

4. 分代收集算法
分代收集算法是根据对象的存活周期的不同,将内存划分为不同的区域,然后针对不同的区域采用不同的垃圾回收算法。一般是将Java堆分为新生代和老年代,新生代的对象存活率低,每次垃圾回收都会有大量对象需要被回收,所以该区域采用复制算法。而老年代的对象存活率高,该区域采用标记-清除算法或标记-整理算法。这样做的好处是可以提高JVM的回收效率,避免了只采用某一种算法的缺陷。当前商业虚拟机都是采用该种算法进行垃圾回收。
在这里插入图片描述

  • Eden空间和Survivor空间的默认大小比例是8:1,可通过 -XX:SurvivorRatio 命令调整这个比例。
  • 新生代和老年代默认内存大小的比例是1:2,可用过 -XX:NewRatio 命令调整这个比例。
  • 对象如何晋升到老年代:
    • 经历一定Minor次数依然存活的对象,该次数可通过 -XX:MaxTenuringThreshold 命令调整,默认:15。
    • Survivor空间中存放不下的对象,会存储在老年代。
    • 新生成的大对象会存储在老年代中,可通过 -XX:+PretenuerSizeThreshold 命令调整。
  • GC的分类:
    • Minor GC:从新生代回收内存。
    • Full GC:回收整个Java堆空间的内存,包括新生代和老年代。Full GC比Minor GC慢很多,大概有10倍的差距,但是Full GC执行的频率比较低。
    • Major GC:一般来说和Full GC是等价的,由于名词解读的混乱,当说Major GC时一定要问清楚是指Full GC还是仅指从老年代回收内存。
  • 触发Full GC的条件:
    • 老年代空间不足
    • 永久代空间不足(JDK1.7之前)
    • CMS GC时出现promotion failed,concurrent mode failure时
    • Minor GC晋升到老年代的平均大小大于老年代的剩余空间
    • 调用System.gc()
    • 使用RMI来进行RPC或管理的JDK应用,没小时执行一次Full GC
几个概念
  • Stop The World
    • JVM由于要执行GC而停止应用程序的执行。
    • 任何一种GC算法中都会发生。
    • 多数GC优化都是通过减少stop-the-world发生的时间来提高程序性能。
  • 安全点(Safepoint)
    • 程序执行时并非在所有地方都能停下来开始GC,而是在到达安全点时才会暂停。
    • 在可达性分析过程中对象引用关系不会发生变化的点。
    • 产生安全点的地方:方法调用、循环跳转、异常跳转等。
    • 安全点数量得适中,太少会使GC等待时间太长,太多会增加运行时的负荷。

垃圾收集器

在这里插入图片描述
1. Serial收集器

  • 单线程收集,进行垃圾收集时,必须暂停所有工作线程。
  • 简单高效,Client模式下默认的新生代收集器。
  • 采用复制算法。
  • 使用 -XX:+UseSerialGC 命令可以切换使用该收集器。

2. ParNew收集器

  • 多线程收集,其余的行为、特点和Seria收集器一样。
  • 单核执行效率不如Serial,在多核下执行才有优势。
  • 采用复制算法。
  • 使用 -XX:+UseParNewGC 命令可以切换使用该收集器。

3. Parallel Scavenge收集器

  • 比起关注用户线程停顿时间,该收集器更关注系统的吞吐量。
  • 在多核下执行才有优势,Server模式下默认的新生代收集器。
  • 采用复制算法。
  • 使用-XX:+UseParallelGC 命令可以切换使用该收集器。
  • 使用-XX:+UseAdaptiveSizePolicy 命令开启自适应调节策略,该命令会动态调整Java堆中各区域的大小及进入老年代的年龄。
  • 吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)

4. Serial Old收集器

  • 单线程收集,进行垃圾收集时,必须暂停所有工作线程。
  • 简单高效,Client模式下默认的老年代收集器。
  • 使用标记-整理算法。
  • 使用 -XX:+UseSerialOldGC 命令可切换该收集器。

5. Parallel Old收集器

  • 多线程,吞吐量优先。
  • 使用标记-整理算法。
  • 使用 -XX:+UseParallelOldGC 命令可切换该收集器。

6. CMS收集器

  • 垃圾回收的六个步骤:
    • 初始标记:stop-the-world
    • 并发标记:并发追溯标记,程序不会停顿。
    • 并发预清理:查找执行并发标记阶段从新生代晋升到老年代的对象。
    • 重新标记:暂停虚拟机,扫描CMS堆中的剩余对象。
    • 并发清理:清理垃圾对象,程序不会停顿。
    • 并发重置:重置CMS收集器的数据结构。
  • 使用标记-清除算法。
  • 使用 -XX:+UseConcMarkSweepGC 命令可切换该收集器。

7. G1收集器

  • 并发和并行
  • 分代收集
  • 空间整合
  • 可预测的停顿
  • 将整个Java堆内存划分成多个大小相等的Region。
  • 年轻代和老年代不再物理隔离。
  • 使用复制+标记-整理算法
  • 使用 -XX:+UseG1GC 命令可切换该收集器。

8. Epsilon GC

  • JDK11中新引入的垃圾收集器。
  • 一个处理内存分配但不实现任何实际内存回收机制的GC,一旦可用堆内存用完,JVM就会退出。
  • 主要用途:
    • 性能测试,可以帮助过滤掉GC引起的性能假象。
    • 内存压力测试。
    • 非常短的JOB任务。
    • VM接口测试。
    • Last-drop 延迟&吞吐改进。

9. ZGC

  • 7
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

成汐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值