26

ビューの作成時に Context/Activity のメモリ リークを防止するためのベスト プラクティスを研究してきましたが、クラスの静的フィールドに関して何が許可され、何が許可されないかについて明確な答えを見つけることができないようです。

この形式のコードがあるとしましょう:

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 を 1 回インスタンス化すると (View が最初に膨張したときに発生します)、静的変数は常に存在し、アプリケーション自体が終了するまでそこに留まるように見えます。その場合、Bitmaps と Canvas オブジェクトも開いたままになり、ヒープがいっぱいになるのを妨げているのは何ですか?

私が何度も繰り返し見た唯一のステートメントは、コンストラクターで示したように静的コンテキストをリークできないということですが、それを超えることはありません。本当にそれしかできないんですか?

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

定数の場合、それが発生することを望みますが、定数の量とそれらが占有するメモリの量は大きくないため、通常は悪くありません。Contextまた、定数は、やのように大量のメモリを消費する他のインスタンスを参照しません (すべきではありません) Bitmap

静的変数を介してメモリ リークが発生する可能性に加えて、すべてのインスタンスに対して同時に 1 つだけを保持したくない場合は、問題が発生する可能性もあります。たとえば、変数Bitmapに を保存する場合、 2 つの異なる画像を持つことはできません。2 つの が同時に表示されない場合でも、新しいインスタンスごとに古いイメージが上書きされる可能性があり、別のインスタンスに戻ると予期せず間違ったイメージが表示されるため、問題が発生する可能性があります。ここでは使用したくないとほぼ確信しています。SurfaceViewstaticSurfaceViewSurfaceViewstatic

内部クラスが であるという事実は、静的変数を使用する必要があるという意味ではありません。クラスでインスタンス変数 (ではないもの) を使用できないためstatic class、メソッドのように動作することを意味します。staticstatic

メモリ リークを回避するには、静的変数をまったく使用しないでください。特別なこと (クラスのインスタンスのカウントなど) をしない限り、それらを使用する必要はありません。定数は問題ありません。

于 2012-08-10T20:18:24.350 に答える