Java中GC(垃圾回收)与内存泄漏:如何检测循环引用对象的可回收性
Java中循环引用对象的GC回收问题解答
结论
voidTest方法执行完毕后,内部创建的person和room对象会被GC回收,即使它们存在循环引用。
原理解释
Java的垃圾回收采用可达性分析算法,核心逻辑是:以GC Roots(栈帧局部变量、静态变量、常量引用、JNI引用等)为起点,遍历所有对象的引用链,只要对象不在任何一条从GC Roots出发的引用链上,就会被标记为可回收对象。
在你的代码中:
- 当
voidTest执行完毕,方法对应的栈帧会从Java虚拟机栈中弹出,栈帧里的person和room局部变量(属于GC Roots的一部分)会被销毁。 - 堆内存中的
Person和Room对象虽然互相引用,但已经没有任何GC Roots能到达它们,因此属于不可达对象,满足GC回收条件。
这里需要注意:循环引用只会影响引用计数法的垃圾回收(比如Python早期的GC),但Java的可达性分析完全不受循环引用的影响。
测试方法
方法1:重写finalize()方法观察回收日志
finalize()方法是对象被回收前会调用的方法(仅用于测试,不推荐生产代码使用),通过打印日志可以验证对象是否被回收:
class Main{ public static void main(String[] args) { voidTest(); // 手动触发GC(仅测试用,实际GC时机由JVM决定) System.gc(); // 暂停线程,给GC执行时间 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } public static void voidTest(){ Person person = new Person(); Room room = new Room(); room.person = person; person.room = room; // 修正原代码拼写错误:roon -> room } } class Room{ public int id; public Person person; @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("Room对象已被GC回收"); } } class Person{ public String name; public Room room; @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("Person对象已被GC回收"); } }
运行代码后,如果控制台输出两个回收日志,说明对象已被成功回收。
方法2:使用WeakReference和ReferenceQueue验证
弱引用(WeakReference)的特点是:只要GC发现弱引用指向的对象没有强引用存在,就会回收该对象,并将弱引用放入关联的引用队列中。通过检查引用队列可以判断对象是否被回收:
import java.lang.ref.WeakReference; import java.lang.ref.ReferenceQueue; class Main{ public static void main(String[] args) { ReferenceQueue<Person> personQueue = new ReferenceQueue<>(); ReferenceQueue<Room> roomQueue = new ReferenceQueue<>(); voidTest(personQueue, roomQueue); // 手动触发GC System.gc(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 检查引用队列,若不为空说明对象已被回收 System.out.println("Person对象是否被回收:" + (personQueue.poll() != null)); System.out.println("Room对象是否被回收:" + (roomQueue.poll() != null)); } public static void voidTest(ReferenceQueue<Person> pQueue, ReferenceQueue<Room> rQueue){ Person person = new Person(); Room room = new Room(); // 用弱引用包装对象并关联引用队列 WeakReference<Person> personRef = new WeakReference<>(person, pQueue); WeakReference<Room> roomRef = new WeakReference<>(room, rQueue); room.person = person; person.room = room; // 移除局部变量的强引用 person = null; room = null; } } class Room{ public int id; public Person person; } class Person{ public String name; public Room room; }
运行代码后,如果输出true,说明对应对象已被GC回收。
内容的提问来源于stack exchange,提问作者Kien Truong Quang
相关产品推荐
相关产品推荐

