1. 理解Java内部类与外部类引用关系
在Java开发中,内部类持有外部类引用是一个容易被忽视但极其重要的语言特性。这个问题我第一次遇到是在一个内存泄漏排查场景中——当时我们的Android应用频繁发生OOM崩溃,通过MAT工具分析堆转储文件后,发现大量Activity实例被匿名内部类隐式持有导致无法回收。
1.1 现象还原与本质分析
所有非静态内部类(包括成员内部类、方法内部类和匿名内部类)都会隐式持有一个指向外部类实例的引用。这个引用存储在内部类的this$0字段中,可以通过反射验证:
java复制public class Outer {
class Inner {
void printRef() {
System.out.println(this.getClass().getDeclaredFields()[0].getName()); // 输出this$0
}
}
}
这种设计源于Java的语言规范:
- 内部类需要访问外部类的成员(包括private成员)
- 编译器自动在内部类构造器中添加外部类参数
- 生成合成字段(synthetic field)保存引用
1.2 内存泄漏典型场景
在Android开发中常见以下危险模式:
java复制public class MainActivity extends Activity {
private static Thread backgroundThread;
void startBackgroundTask() {
backgroundThread = new Thread(new Runnable() { // 匿名内部类隐式持有Activity引用
@Override public void run() {
while(true) { /* 长时间运行 */ }
}
});
backgroundThread.start();
}
}
当Activity销毁时,由于静态线程持有Runnable匿名内部类实例,而内部类又
