在 Java 中,静态变量位于堆上,并在类加载时分配。实例变量的垃圾回收资格与其实例相关联。
使用 value-type(int, bool, double, etc.) 静态变量不会泄漏类的实例。当您允许非值类型的静态变量时,您可以泄漏这些静态变量引用的任何内容。
考虑一个简单的类
public class Activity extends Context {
static int willNotLeakActivity = 0;
static Context mayLeakActivity = new Context();
//if you call activityA.leakyMethod(activityA); you will leak activityA
public void leakyMethod(Context context){
mayLeakActivity = context;
}
//this method won't leak the instance
public void safeMethod(int arg){
willNotLeakActivity = arg;
}
}
如果您在静态变量中保留对 Activity 对象的引用(即使引用类型是 Context),您将泄漏 Activity 对象。
请记住,Android 不是在真正的 JVM 上运行,而是在 Dalvik VM 上运行,因此理论上您的结果可能会有所不同,但我会非常惊讶地发现 Dalvik 在 GC 资格方面有所不同(我没有我自己不会遇到任何问题)。
编辑 - 再次查看这个问题,我认为这可能会澄清一些理解:只要可以通过遵循 GC 根的引用链来访问对象,它就不会成为垃圾收集的条件。Activity 对象由 Android 进程实例化并正常保持活动状态(我假设它保持活动状态至少类似于static void main(string[] args)
.
一旦系统调用 yourActivityInstance.onDestroy() 并释放引用,该对象就有资格被 GC(以及随后它引用的所有对象),除非您的活动实例可以通过另一个引用从 GC 根访问。如果这个引用的持有时间超过了它应该持有的时间(阅读:无限期地),你已经泄漏了这个对象,因为 GC 不能确定它可以安全地释放泄漏对象的资源。
这个引用的保存方式无关紧要(静态或非静态,最终或非最终)。只要可以从 GC 根访问对象(至少是静态方法中的本地和范围内变量,加载类中的静态字段),您就会泄漏。