GC Root
GC Roots 是 Java 垃圾回收机制中判断对象是否存活的"根节点"。用大白话说:如果一个对象能被 GC Roots 直接或间接访问到,它就不会被回收;否则就会被当成垃圾清理。
🌳 GC Roots 的四种类型(附生活类比)
1. 虚拟机栈中的局部变量
- 场景:你调用了一个方法,方法内部 new 了一个对象
- 例子:
public void myMethod() { Object obj = new Object(); // obj 是局部变量,属于 GC Root // 方法未结束前,obj 不会被回收 }
- 类比:就像你正在用的水杯,只要你在用(方法未结束),杯子不会被收走。
2. 方法区中的静态变量
- 场景:用
static
关键字修饰的变量 - 例子:
public class MyClass { static Object staticObj = new Object(); // staticObj 是 GC Root }
- 类比:公共书架上长期摆放的书籍,谁都可以随时取用,不会被清理。
3. 本地方法栈中的 JNI 引用
- 场景:通过 JNI(Java Native Interface)调用的本地代码(如 C/C++)引用的对象
- 类比:跨国快递的包裹单,虽然用外语写的,但依然要保留直到签收。
4. 活跃线程对象
- 场景:正在运行的线程(如
Thread
对象) - 例子:
Thread thread = new Thread(() -> { while (true) { /* 无限循环 */ } }); thread.start(); // thread 对象是 GC Root
- 类比:正在工作的员工,只要还在职,他的工位不会被清空。
🔍 GC Roots 的追踪原理(图示)
想象 GC Roots 是一棵大树的根,所有被根直接或间接连接的对象(树枝、树叶)都是"存活"的,而断开的树枝会被回收:
GC Roots → 对象A → 对象B → 对象C
↘ 对象D
- 对象A、B、C、D 都不会被回收
- 如果断开对象A和B的引用,则B、C 会被回收
❓ 面试常见问题
-
问:
String str = new String("Hello");
中,str
是 GC Root 吗?
答:是的!只要str
在方法栈中(方法未执行完),它指向的对象就不会被回收。 -
问:静态变量被置为
null
会怎样?
答:原本被静态变量引用的对象会失去 GC Root 保护,可能被回收。
💡 记忆技巧
把 GC Roots 想象成"钉子":只要对象被钉子钉在内存墙上,就不会掉下来(被回收)。钉子类型就是上述四种!