26

我一直在研究在创建视图时防止上下文/活动内存泄漏的最佳实践,但对于类中的静态字段,我似乎无法找到明确的答案。

假设我有一个这种形式的代码:

public class MyOuterClass extends Activity{
   private MyInnerClass;
   MyInnerClass = (MyInnerClass) findViewById(<XML call here>);
   MyInnerClass.myXInt = 3;

   // onCreate(), onResume(), etc.

   public static class MyInnerClass extends SurfaceView implements Runnable{
      // Safe variables?
      private static int myXInt, myYInt;
      private static boolean myBoolean;
      // Potentially safe?
      private static Canvas myCanvas;
      // Definitely bad.
      private static Context myContext;

      public MyInnerClass(Context context){
         myContext = context;        // This is bad.
      }
   }
}

我对 JVM 实际上认为 MyInnerClass 的 ClassLoader 是什么感到有些困惑。从技术上讲,因为它是一个 SurfaceView 对象,所以一旦应用程序实例化 MyInnerClass 一次(这发生在 View 第一次膨胀时),静态变量似乎应该始终存在,然后保持在那里直到应用程序本身终止。如果是这样,是什么阻止位图和画布对象保持打开状态并填满堆?

我看到的唯一声明是你不能像我在构造函数中显示的那样泄漏静态上下文,但它永远不会超出这个范围。这真的是你唯一不能做的事情吗?

4

2 回答 2

46

在 Java/Android 中,static变量或常量不会被垃圾回收。一旦持有它的类通过类加载器加载,它就会停留在那里。对于您的应用程序中的所有类,类加载器始终是相同的,并且它具有对您的所有类的静态引用(例如MyInnerClass.class)。由于类加载器不会消失,因此您的类也不会这样做,因为它们被引用,因此不可回收。

就像你的例子一样

public class SomeClass extends SurfaceView {
  private static Context myContext;

  public MyInnerClass(Context context){
     myContext = context;        // This is bad.
  }
}

那确实很糟糕。即使不存在对SomeClass存在的引用(例如Activity,显示您的自定义已结束),对(以及任何其他变量/常量SurfaceView的静态引用将保留。您可以认为它们都已泄漏,因为不可能对它们进行垃圾收集等。如果你有一个常规变量引用某个东西,那么一旦包含该变量的实例不再引用它,整个实例包括它对其他东西的引用都可以并且将会被垃圾收集。Java甚至可以很好地处理循环引用。ContextstaticSomeClassContext

对于常量,您希望发生这种情况,这通常还不错,因为常量的数量和它们占用的内存量并不大。常量也不(不应该)引用其他占用大量内存的实例,例如Contextor Bitmap

除了通过静态变量创建内存泄漏的可能性之外,如果您不想同时为所有实例提供一个单一的东西,您也可能会产生问题。例如,如果您将您的 保存BitmapSurfaceView一个static变量中,您就不能有两个不同的图像。即使两个SurfaceViews 没有同时显示,您也可能会遇到问题,因为每个新实例都可能会覆盖旧图像,如果您返回另一个实例,您会SurfaceView意外显示错误的图像。我几乎可以肯定你不想在static这里使用。

您的内部类是 a 的static class事实并不意味着您必须使用静态变量 - 它只是意味着它的行为更像是一个static方法,因为它不能在您的类中使用实例变量(那些不是static)。

为了避免内存泄漏,您根本不应该使用静态变量。除非您做特殊的事情(例如计算类的实例),否则无需使用它们。常数很好。

于 2012-08-10T20:18:24.350 回答
-1

本文讨论可变静态字段:http: //javabook.compuware.com/content/memory/problem-patterns/memory-leaks.aspx。基本上,避免使用它们并改用常量。

于 2015-02-19T18:50:30.427 回答