【大白话说Java面试题 第69题】【JVM篇】第29题:GC Roots 有哪些?
PDF大白话说Java面试题 — 02-JVM篇第29题GC Roots 有哪些回答核心考点GC Roots 是可达性分析算法的起点。大厂面试要求准确列出所有类型的GC Roots并能解释为什么某些对象会成为GC Root以及常见的误解如静态变量是否一定能阻止GC。1. GC Roots 的完整定义GC Roots 是指必须存活的对象集合从它们出发可达的对象被标记为存活不可达的则判定为可回收。2. GC Roots 的5种类型JDK 8及之前类型说明示例虚拟机栈引用每个栈帧中的局部变量表引用的对象方法内的局部变量、参数静态属性引用方法区中类的静态变量引用的对象private static User user new User();常量引用方法区中运行时常量池引用的对象字符串常量abc、Class对象JNI引用Native Stack本地方法栈中JNI全局/局部引用的对象JNIEnv-NewObject(...)活跃线程所有正在运行的Thread对象Thread.currentThread()3. 各类型的深度解释面试加分项3.1 虚拟机栈中的引用最常用包括局部变量、方法参数、临时变量示例voidfoo(){ObjectonewObject();// o 是GC Rootinti0;// 基本类型不是引用不算}注意方法执行完出栈后这些GC Root消失对应对象变为不可达。3.2 静态属性引用属于类级别类未被卸载则静态变量一直存活。常见误解设置static obj null后原对象不再被GC Root引用可能被回收。示例classCache{staticMapString,ObjectmapnewHashMap();// map 是GC Root}内存泄漏高发地静态集合类添加对象后忘记清理。3.3 常量引用字符串常量池中的对象如helloClass对象如String.class基本类型包装类常量如Integer.valueOf(1)缓存的 -128~127 对象注意常量池中动态添加的字符串intern()也是GC Root直到JVM回收该常量。3.4 JNI 引用Global JNI Reference显式NewGlobalRef创建需手动DeleteGlobalRef否则泄漏Local JNI Reference本地方法栈帧内的引用方法退出后自动释放场景Android NDK / JNI 开发中忘记删除GlobalRef导致内存泄漏。3.5 活跃线程每个正在运行的线程本身就是GC Root线程栈程序计数器线程内部的局部变量也是从该线程Root可达的4. 其他隐藏的 GC RootsJDK 8类型说明系统类加载器加载核心类rt.jar的BootClassLoaderJVM内部对象SystemDictionary、JVMTI标记的对象同步监视器被synchronized锁住的对象StackMapTableJVM内部栈映射表引用的对象Finalizer引用尚未执行finalize()的对象会被Finalizer队列持有5. 关键区别哪些不是 GC Roots对象是否是GC Root原因方法内的局部变量未执行到否栈帧未入栈不存在引用不可达的静态变量否类已被卸载如自定义ClassLoader卸载时普通对象字段否需要通过GC Root链到达软/弱/虚引用指向的对象否引用本身特殊处理但引用的目标对象需链到Root才算存活6. 大厂面试追问Q1静态变量引用的对象一定是 GC Root 吗A是的只要该类未被卸载。在自定义ClassLoader场景中类可被卸载如OSGi、热部署卸载后静态变量不再作为GC Root。Q2字符串常量池中的对象永远不会被回收吗A不会。JDK 7字符串常量池在堆中Full GC时若常量无引用可以被回收。例如String s a; s null;触发Full GC后a可能被回收。Q3ThreadLocal中的变量是 GC Root 吗AThreadLocalMap的key是弱引用不是直接GC Root但当前Thread对象是GC Root从Thread可以访问到ThreadLocalMap进而访问到key。所以只要线程活着ThreadLocalMap的引用链就不断。Q4GC Roots 的数量一般是多少A大应用中可达数万甚至更多每个栈帧的局部变量、每个静态变量、每个活跃线程等。GC Roots 过多会导致可达性分析变慢。Q5可达性分析和引用计数法的区别A引用计数无法解决循环引用A-B, B-A而可达性分析从GC Roots出发不可达才回收能正确处理循环。7. 实战如何查看一个对象是否被 GC Root 引用工具MATMemory Analyzer Tool打开 heap dump选择对象 →Path to GC Roots→ 排除软/弱/虚引用显示从该对象到某个GC Root的最短路径示例结果java.lang.Object 0x7f3a2c8 → com.example.Cache.map (静态字段) → java.util.HashMap 0x7f3a3d0 → ... (到GC Root)8. 总结对比表面试速记GC Root 类型生命周期常见泄漏风险虚拟机栈引用方法执行期间无自动释放静态属性引用类生命周期通常永久高静态集合常量引用JVM常量池回收时中intern字符串JNI Global引用手动删除高忘记DeleteGlobalRef活跃线程线程运行期间中线程池任务未释放Context面试官想要的满分总结“GC Roots 是可达性分析的起点主要包括5类栈帧局部变量、静态变量、常量、JNI引用、活跃线程。特别注意静态变量引用的对象只要类未卸载就一直是GC Root容易引发内存泄漏字符串常量池中的对象在JDK 7中位于堆上Full GC时可能被回收。排查内存泄漏时用MAT的Path to GC Roots功能找到是哪种Root阻止了对象回收就能定位问题根源。”觉得对您有帮助麻烦点点关注啦您的关注是我创作的最大动力~