JVM内存回收机制和算法

JVM内存回收机制和算法

内存回收机制

内存回收机制主要针对堆内存进行管理,栈、本地方法栈和计数器等内存区域的分配与回收通常在编译期确定并在线程执行完毕后自动清理,相比之下,堆内存的回收更为复杂。下面是通过几个问题详细说明内存回收机制的内容:

  1. 可回收堆内存的判定
    可回收的堆内存对象是指那些在当前引用状态下无法再被访问的对象。

    引用计数算法
    每个对象都有一个引用计数器,每当有新的引用指向该对象时计数器+1,引用被释放时计数器-1。当计数器为0时,该对象被视为“无用”,其占用的内存可以被回收。然而,引用计数算法在处理循环引用时存在问题,即当两个或多个对象相互引用但外界无法访问时,即使引用计数不为0,也会造成这些对象实际上无法访问,从而导致内存无故占用。image.png

    根搜索算法
    JVM采用根搜索算法,通过追踪由栈内存或方法区引用的对象来构建对象引用链。如果对象可以从GC Roots通过引用链访问到,则表明对象仍然存活,其内存不应被回收;反之,若无法通过引用链找到对象,则认为该对象是废弃的,应当回收内存。在Java中,GC Roots包括:

    • 虚拟机栈(栈帧中的本地变量表)引用的对象
    • 方法区中的类静态属性引用的对象
    • 方法区中的常量引用的对象
    • 本地方法栈中JNI引用的对象

    一个对象被判定死亡,至少需要经历两次标记过程。在根搜索后,若对象与GC Roots间没有相连的引用链,它将被标记并进行筛选,筛选条件是判断对象是否有必要执行finalize()方法。如果对象未覆盖finalize()方法,或该方法已被调用过,JVM将视其为“无需执行”。

    finalize()方法仅会被系统自动调用一次,若对象面临下一次回收,即使仍有finalize()方法未执行,也不会再次调用。

  2. 确定可回收对象后的处理
    在确定了哪些内存需要回收后,GC机制会给那些重写了finalize()方法的对象一次自救的机会,即执行其重写的finalize()方法。若在此方法中对象重新与引用关联从而使内存区域再次变得可达,那么GC在此次回收中将不会回收这部分内存。不过,这种自救机会只有一次,下一次回收时,无论finalize()方法是否执行,GC都会直接回收。

    堆内存对象的回收是如此处理,而方法区中保存的类信息和常量池内存也需要回收,但由于类和常量池的使用相对稳定,回收过程相对缓慢且不够高效,通常只有在确认类不再使用且不被反射调用时才会卸载类,而常量池中不再使用的常量才会被释放。

内存回收策略与算法

  • 标记-清除算法(应用于老年代)
    该算法首先标记出所有需要回收的对象,在标记完成后统一回收这些对象。

主要缺点是标记和清除效率不高,并且垃圾收集后可能出现内存碎片化严重的问题。

image.png

  • 复制算法(应用于新生代)把内存分为大小相同的两块,每次只使用其中一块,当一块内存耗尽时,将存活对象复制到另一块并清空先前那一块。image.png
  • 标记-整理算法(应用于老年代)
    先标记存活对象,然后将所有存活对象向内存一端移动,最后清除边界外的部分,以避免内存碎片化的问题。image.png分代收集算法
    商业虚拟机普遍采用“分代收集”算法,将Java堆分为新生代和老年代,根据不同年代对象的生存周期特点,采用最适合的收集算法。其中,标记-清除算法易产生内存碎片,标记-整理算法虽解决了碎片问题但增加了时间消耗,复制算法则可能造成内存浪费。
  1. 内存分配与回收的全过程
    新创建的对象优先被分配到堆内存的Eden区,当Eden区空间不足时,对象会进到Survivor区。若Survivor区也无法容纳,将触发新生代的minor GC。在GC过程中,若Survivor区仍然无法放下对象,这些对象将晋升至老年代。若对象失去引用,存活对象将被移动到Survivor区,Eden区内存被清理。对于大对象和长期存活对象,通常会选择直接分配到老年代,以节省内存分配成本。此外,根据Survivor区中相同年龄对象大小的变化,适时将其移入老年代。在每次执行minor GC时,若即将晋升至老年代的对象总大小超过老年代剩余空间,会触发一次Full GC以获得更多空间。

image.png

  1. 通过VisualVM工具观察内存管理的实例
    通过一个具体的Java程序实例,借助VisualVM工具可以直观展现虚拟机内存分配和回收的过程。在示例中,程序循环创建新对象,并在每次循环结束后将引用指向新对象,原对象变为无引用状态。随着时间推移,JVM的minor GC会回收这些废弃对象占用的内存。通过VisualVM观察到的实时内存状况展示了新生代对象从Eden区分配、经历minor GC后存活对象在Survivor区之间迁移,以及最终可能晋升到老年代的整个过程。每次minor GC都会将一个Survivor区(from Space)清空,并将存活对象迁移到空闲的Survivor区(to Space),若to Space不足以容纳所有存活对象,将触发分配担保机制,将对象直接晋升至老年代。

原文链接 汉源魂博客 | 汉源魂-专注于分享-spring-docsify-boot

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值