很明显,我理解错了什么。我知道将变量放入应用程序上下文中可以使它们保持不变而不会造成问题。
关于内存泄漏的一般问题:有很多关于内存泄漏的信息,但我找不到任何清晰地总结所有信息的内容。请问是否有哪些推荐的资源可以全面解释这个问题。
在Java中,静态变量存储在堆上,并在它们的类加载时分配。实例变量的垃圾收集资格与它们的实例相关联。
使用值类型(int、bool、double等)的静态变量将不会泄漏类的实例。当您允许非值类型的静态变量时,您可能会泄漏这些静态变量引用的任何内容。
考虑一个简单的类:
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回收(随后,所有它引用的对象也将被回收),除非您的activity实例通过另一个引用从GC根可达。如果这个引用被保留的时间比应该保留的时间长(即无限期),则会泄漏此对象,因为GC不能确定是否可以安全地释放泄漏对象的资源。
无论如何保留这个引用(静态或非静态,final或非final),只要一个对象可以从GC根(至少是静态方法中的局部变量和范围内变量,已加载类中的静态字段)到达,您就会泄漏。