Android静态final导致的内存泄漏问题

5
问题在于使用静态常量可能导致内存泄漏:我一直在寻找有关如何避免 Android 应用程序中的内存泄漏的信息。一个大问题是使用 private static final 定义常量。显然这是定义常量的方法。但是,static final 意味着它会在旋转后仍然存在,并且意味着 Activity 无法被清除。
很明显,我理解错了什么。我知道将变量放入应用程序上下文中可以使它们保持不变而不会造成问题。
关于内存泄漏的一般问题:有很多关于内存泄漏的信息,但我找不到任何清晰地总结所有信息的内容。请问是否有哪些推荐的资源可以全面解释这个问题。

你应该提供更多信息来改进这个问题。你的应用程序是否遇到了内存泄漏的问题,还是你只是听说在Android平台上使用静态常量会导致内存泄漏的影响? - Chris Bye
我目前没有出现内存泄漏问题(之前因为故意模仿内存泄漏的例子而出现过内存泄露)。我正在尝试理解以避免引发内存泄漏。对于这个问题的一些回答提供了很好的信息,我会花些时间来研究它们。首先需要澄清的是常量的静态final是可以的(也建议使用),但不要将静态final用于上下文类型(如Activity)或视图和可绘制对象,因为这些对象都有对Activity的引用。 - DerekD
5个回答

13
这段信息是错误的。将变量定义为“static final”不会因其被标记为静态和不可变而导致任何内存泄漏。但这并不意味着你不能通过这样做来创建内存泄漏。要避免的一件事情是创建一个静态变量,它的类型是上下文(例如活动)。当你创建一个静态引用到上下文时,你可能会创建内存泄漏。静态变量意味着整个应用程序只有一个该变量的副本,并跨该类的所有实例存在。这也意味着它会一直存在于内存中,直到明确清除它或关闭应用程序。静态变量是类级别的变量,不附加到任何特定对象实例。例如,当你创建一个'public static final string myString ="Hello"',你永远不会导致内存泄漏。这种方式定义一个常量实际上会节省内存,相比使用'public final string myString = "Hello"',因为没有静态的话,每个该类实例都会创建一个内存位置来存储该字符串,而不是只有一个副本供所有实例使用。

5

在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根(至少是静态方法中的局部变量和范围内变量,已加载类中的静态字段)到达,您就会泄漏。


2
这是一段非常好的视频,涉及了所有Android内存管理方面的内容,并详细介绍了如何检测内存泄漏。虽然不完全符合你的要求,但在同一主题中值得一提。 http://www.youtube.com/watch?v=_CruQY55HOk

0

如果您没有引用Activity本身,常量不会导致内存泄漏。在您的Activity中使用(例如String)常量是没有问题的。

有两个很好的资源涉及到内存泄漏的主题:

  • 来自Android开发者博客的描述这里
  • 关于内存管理的Google IO演示这里

0

静态常量不一定会持续活动并且非常标准。问题在于当您有一个静态变量,它持有对您的活动的引用(例如视图或可绘制对象),这些引用超出了该活动的预期生命周期。

内存分析的良好起点在这里, 在这里, 和 在这里。您还可以通过调查垃圾回收的工作原理来更好地服务自己。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接