
一文讲透 JVM 内存回收GC Roots 与可达性分析如何决定对象生死【免费下载链接】jvm JVM 底层原理最全知识总结项目地址: https://gitcode.com/gh_mirrors/jvm9/jvmjvm 项目系统梳理了 JVM 底层原理这篇聚焦 JVM 内存回收的判定核心——GC Roots 与可达性分析讲清 JVM 如何判断对象存活以及 Java 内存泄漏怎么排查。 泄漏现场复盘GC 凭什么判定对象该死先还原一个高频事故服务跑了几周堆被某个缓存 Map 一点点占满GC 越来越频繁最后 OOM。dump 出来发现对象明明没人用虚拟机为什么不动手关键在于可达性分析虚拟机不数引用个数而是从一组固定起点出发沿引用链往下找——凡是还能找到的都算活着找不到的才是垃圾。判定标准就这一条与 GC Roots 直接或间接相连即存活否则可回收。那个缓存 Map 收不掉是因为它挂在 static 字段上起点直接够得着。而 GC Roots 刻意不含堆对象之间的互相引用所以两个对象互相指着对方也照样会被判死循环引用在这套机制下天然不成立。从哪查起GC Roots 的四大锚点怎么定把 JVM 想成一张电网GC Roots 是四个总开关接出的干线对象是干线上的设备引用就是电线。巡检只从干线往沿线查——供电还连得上的设备继续运行与干线彻底断开的孤岛设备一律判废回收。技术翻译这四个起点是虚拟机规定死的可达性遍历只能从这里发起。虚拟机栈的本地变量表当前栈帧里的参数和局部变量本地方法栈JNI 调用中 native 方法持有的引用方法区的常量引用比如字符串常量池中的常量方法区的静态属性类 static 字段指向的对象再强调一次关键事实堆对象互相引用不算锚点这正是循环引用能被正确回收的原因。⚡ 标记三步走一次点名如何完成STW 何时发生巡检不能把全厂拉闸半天所以标记拆成三段初始标记先拉闸STWStop The World只标 GC Roots 直接挂着的对象动作很快并发标记恢复供电巡检队与用户线程同时跑顺着引用链把可达对象全部标一遍重新标记并发期间用户线程仍在改引用再短暂拉闸STW复核修正漏标和错标四种引用强度存活门槛分别是什么JDK 1.2 之后引用分成四档能活着的门槛各不相同强引用最常见的Object obj new Object();只要引用还在就不会被回收软引用用 SoftReference 持有时内存充足就保留堆吃紧才回收——典型场景是缓存弱引用用 WeakReference 持有时下一轮 GC 就收不看内存余量——适合可有可无的辅助数据虚引用用 PhantomReference 时完全挡不住回收只用来感知对象已被回收常配合直接内存做释放跟踪判死刑前的一次机会finalize 复活机制被标成不可达的对象不会立刻消失。若它重写了 finalize() 且尚未执行过会先进入 F-Queue 队列由低优先级线程执行该函数在里面把 this 重新挂到某个引用上obj this;对象就回到可达状态复活成功但机会只有一次。没重生的对象要到下一轮 GC 才会被彻底清除。 内存泄漏避坑清单5 项自查static 字段别当永久停车场临时对象挂上去就收不掉集合用完及时 clear() 或置 nullMap 的 key 尤其注意监听器、回调注册后要反注册否则生命周期跟着宿主走缓存优先 SoftReference / WeakReference给 GC 留后路dump 后用工具从 GC Roots 反查大对象定位谁指住了它至此从起点、标记到引用分档JVM 内存回收的判定逻辑就完整了GC 从不猜测只认能不能从 GC Roots 连上。日常开发中分清四档引用强度、避开上面这些坑绝大多数 Java 内存泄漏都能在一次 dump 里定位到根源。想继续深入可阅读项目内的 GC 算法文档、内存分配与回收策略 与 HotSpot 收集器文档。【免费下载链接】jvm JVM 底层原理最全知识总结项目地址: https://gitcode.com/gh_mirrors/jvm9/jvm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考