JVM 垃圾回收机制

JVM 垃圾回收机制

概述

  • 在内存中已经不再被使用到的内存空间就是垃圾。

垃圾标记阶段(判断对象存活)

垃圾标记阶段用于判断对象是否可回收,只有被标记为已死亡的对象,GC才会在执行垃圾回收时,释放其占用的内存空间。

在Java虚拟机中,判断对象是否存活的两种方式:

  • 引用计数法
  • 可达性分析法

引用计数法

说明:

  • 在对象中添加一个引用计数器。
  • 当对象被引用+1,当对象失去引用-1;引用计数为0时,对象不再被引用,可以被回收。

优点:

  • 简单
  • 高效。

缺点:

  • 需要单独的字段存储计数器,增加了内存开销;每次赋值需要更新计数器,增加了时间开销。
  • 无法解决循环引用问题,目前在Java中几乎不使用这种算法。
objA.name = objB;
objB.name = objA;

可达性分析法

可达性分析法是以 GC Roots 为起点,从这些节点开始向下搜索,搜索所走过的路径被称为引用链,当一个对象没有被任何引用链相连时,则证明该对象是不可用的,表示可以被回收。

在这里插入图片描述

GC Roots 说明:

GC Roots 是一组活跃的引用。GC Roots 对象包含:

  • 虚拟机栈(栈帧中的局部变量表)中引用的对象
  • 方法区中的静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI引用的对象
  • 同步锁synchronized持有的对象

垃圾回收阶段

当区分出内存中存活对象和死亡对象后,GC接下来的任务是执行垃圾回收,释放掉死亡对象所占用的内存空间。

标记-清除算法

算法过程:

该算法分标记和清除两个阶段:

  • 标记阶段:标记所有需要回收的对象。
  • 清除阶段:统一回收所有被标记的对象。

在这里插入图片描述

优点:

  • 算法简单、实现简单。

缺点:

  • 效率问题:标记和清除这两个过程效率不高。大部分对象都是朝生夕死的,因此需要大量标记对象和回收对象。
  • 空间问题:标记-清除后,会产生大量的内存碎片。内存碎片太多可能会导致需要分配较大对象时,无法找到足够的连续空间,从而提前触发另一次垃圾收集动作。

场景:

  • 标记-清除算法适合老年代。

复制算法

算法过程:

  • 将内存分为大小相等的两块,每次只使用其中一块。
  • 当这一块内存用完了,将这块内存中存活的对象复制到另一块中,然后一次清除使用的那块内存。

在这里插入图片描述

优点:

  • 效率比标记-清除算法高。
  • 不会产生内存碎片问题。

缺点:

  • 可使用的内存缩小为原来的一半。
  • 当存活对象较多时,需要做多次复制操作,效率将变低。

场景:

  • 复制算法适合新生代。

标记-整理算法

与标记-清除算法类似,多了一个中间操作:整理内存。

标记-清除算法是一种非移动式的回收算法,标记-整理是移动式的。

算法过程:

  • 标记:标记存活对象。
  • 整理:让所有存活的对象向一端移动。
  • 清除:统一清除端以外的对象。

在这里插入图片描述

优点:

  • 一次清除端外区域,比标记-清除算法中的清除效率高。
  • 不会产生内存碎片。

缺点:

  • 移动对象时会触发STW。

场景:

  • 标记-整理算法适合老年代。

分代收集算法

现在主流的虚拟机基本都采用 分代收集算法 ,即根据不同区域特点选择不同垃圾收集算法。

  • 根据对象存活周期不同,堆内存分为:新生代和老年代。
    • 新生代占1/3空间。
      • Eden区占8/10
      • From区占1/10
      • To区占1/10
    • 老年代占2/3空间。
  • 根据特点选择对应的垃圾收集算法。
    • 新生代:对象存活率低,垃圾回收行为频率高,采用复制算法,使用Minor GC。
    • 老年代:对象存活率搞,垃圾回收行为频率低,采用标记-整理和标记-清除算法,使用Full GC。

在这里插入图片描述

算法过程:

在这里插入图片描述

  1. 新创建的对象会先放在Eden区(位于新生代区,该区有大小限制),如果是大对象(如很长的字符串、数组)会直接分配到老年代区,避免频繁的内存复制。
  2. 如果Eden区的空间占满,程序又需要创建对象时,会触发MinorGC,将Eden区的存活对象移动到S0区并销毁垃圾对象,新创建的对象会放在Eden区,这是第一轮MinorGC后的操作。
  3. 当发生第二轮MinorGC后,会将存活Eden区和S0区的存活对象复制到S1区,并清除Eden区和S0区。
  4. 每次MinorGC存活对象的年龄都会加1,当存活对象的年龄达到阀值(默认为15),存活对象会移动到老年代区。
  5. 当老年代区内存不足时,会触发MajorGC,对老年代和新生代进行回收。当老年代内存仍不足时,会产生OOM异常。

优点:

  • 效率高。
  • 空间利用率高。

垃圾收集行为

  • Minor GC(小型垃圾收集):Minor GC主要清理新生代(Young Generation)的内存空间。新生代通常分为Eden区和两个Survivor区(S0和S1),大部分新创建的对象首先被分配到Eden区,当Eden区满时,就会触发Minor GC。
  • Major GC(大型垃圾收集):Major GC主要清理老年代(Old Generation)的内存空间。当对象在新生代存活一段时间后,或者Survivor区无法容纳的对象,会被移动到老年代。当老年代空间不足时,就会触发Major GC。Major GC的开销通常比Minor GC大,因为它涉及到整个堆的清理。
  • Full GC(全量垃圾收集):Full GC涉及到整个堆(包括新生代和老年代)以及方法区的清理。Full GC的开销最大,因为它需要暂停所有的应用线程(Stop-The-World)来进行垃圾收集。

Stop-the-World

Stop-the-World,简称STW,当 Full GC 发生时,会产生应用程序的停顿。停顿产生时整个应用程序都会被暂停,没有任何响应,像卡死一样,这个停顿称为STW。被STW中断的应用程序线程会在完成GC之后恢复。

垃圾收集器类型

查看垃圾收集器种类指令:java -XX:+PrintCommandLineFlags -version

收集器收集对象和算法集器类型说明适用场景
Serial新生代,复制算法单线程简单高效;适合内存不大的情况;
ParNew新生代,复制算法并行的多线程收集器ParNew垃圾收集器是Serial收集器的多线程版本搭配CMS垃圾回收器的首选
Parallel Scavenge吞吐量优先收集器新生代,复制算法并行的多线程收集器类似ParNew,更加关注吞吐量,达到一个可控制的吞吐量;本身是Server级别多CPU机器上的默认GC方式,主要适合后台运算不需要太多交互的任务;
Serial Old老年代,标记整理算法单线程Client模式下虚拟机使用
Parallel Old老年代,标记整理算法并行的多线程收集器Parallel Scavenge收集器的老年代版本,为了配合Parallel Scavenge的面向吞吐量的特性而开发的对应组合;在注重吞吐量以及CPU资源敏感的场合采用
CMS老年代,标记清除算法并行与并发收集器尽可能的缩短垃圾收集时用户线程停止时间;缺点在于: 1.内存碎片 2.需要更多cpu资源 3.浮动垃圾问题,需要更大的堆空间重视服务的响应速度、系统停顿时间和用户体验的互联网网站或者B/S系统。互联网后端目前cms是主流的垃圾回收器;
G1跨新生代和老年代;标记整理 + 化整为零并行与并发收集器JDK1.7才正式引入,采用分区回收的思维,基本不牺牲吞吐量的前提下完成低停顿的内存回收;可预测的停顿是其最大的优势;面向服务端应用的垃圾回收器,目标为取代CMS
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值