【问题标题】:Android memory leak with static finalAndroid内存泄漏与静态最终
【发布时间】:2012-04-04 19:45:37
【问题描述】:

问题是关于使用显然会导致内存泄漏的静态最终常量:我一直在寻找有关如何在 Android 应用程序中不导致内存泄漏的信息。一个大问题是使用 private static final 作为常量。显然这就是应该如何定义常量。但是 static final 意味着它在旋转后挂起,意味着 Activity 不能被清除。

显然我误解了一些东西。我知道将变量放在应用程序上下文中可以让它们在不引起问题的情况下徘徊。

作为关于内存泄漏的一般问题:关于内存泄漏的信息很多,但我找不到任何可以清楚地总结所有信息的信息。任何完全解释的建议。

【问题讨论】:

  • 您应该提供更多信息来改进这个问题。您是否遇到过应用程序内存泄漏的问题,或者您只听说过在 android 平台上使用静态最终常量的泄漏效应?
  • 我现在没有泄漏(我之前确实有泄漏,当我故意按照内存泄漏示例导致它们时)。我试图理解,以免造成内存泄漏。对这个问题的一些回答提供了很好的信息,我会花一些时间来研究它们。第一个澄清是常量的静态最终是可以的(并且推荐),但不要对上下文类型(活动)或视图和可绘制对象使用静态最终,因为它们引用了活动。

标签: android memory-leaks static


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    在 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(以及随后它引用的所有对象),除非您的活动实例可以通过另一个引用从 GC 根访问。如果这个引用的持有时间超过了它应该持有的时间(阅读:无限期地),你已经泄漏了这个对象,因为 GC 不能确定它可以安全地释放泄漏对象的资源。

    如何保存这个引用并不重要(静态或非静态,最终或非最终)。只要可以从 GC 根访问对象(至少是静态方法中的本地和范围内变量,加载类中的静态字段),您就会泄漏。

    【讨论】:

      【解决方案3】:

      这是一个很好的视频,它解决了所有的 Android 内存管理问题,并详细介绍了检测内存泄漏。不完全符合您的要求,但值得在同一线程中提及。

      http://www.youtube.com/watch?v=_CruQY55HOk

      【讨论】:

        【解决方案4】:

        静态常数不一定能保持周围的活动,并且非常标准。当您有一个静态引用您的活动(例如视图或可绘制对象),该引用超出该活动的预期寿命时,就会出现问题。

        内存分析的良好起点hereherehere。只需调查垃圾收集的一般工作原理,您也会得到很好的服务。

        【讨论】:

          【解决方案5】:

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

          有两个很好的资源可以捕获有关内存泄漏的主题:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-08-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-10-08
            • 2011-12-01
            • 1970-01-01
            相关资源
            最近更新 更多