webentwicklung-frage-antwort-db.com.de

Android: Statische Felder und Speicherlecks

Ich habe nach bewährten Methoden zum Verhindern von Speicherverlusten aus dem Kontext-/Aktivitätsspeicher beim Erstellen von Ansichten nachgesehen. Ich kann anscheinend keine eindeutige Antwort darauf finden, was in statischen Feldern in Klassen zulässig ist oder nicht.

Nehmen wir an, ich habe einen Code dieses Formulars:

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.
      }
   }
}

Ich bin etwas verwirrt, was die JVM für ClassLoader für MyInnerClass hält. Technisch gesehen scheint es, da es sich um ein SurfaceView-Objekt handelt, die statischen Variablen immer vorhanden sein, sobald die Anwendung MyInnerClass einmalig instanziiert hat (was geschieht, wenn die View zum ersten Mal aufgeblasen wird) und dann dort verbleiben, bis die Anwendung selbst beendet wird. Wenn dies der Fall ist, was hindert Bitmaps und Canvas-Objekte daran, ebenfalls geöffnet zu bleiben und den Heap aufzufüllen?

Die einzige Aussage, die ich immer und immer wieder sehe, ist, dass statische Kontexte, wie ich sie im Konstruktor gezeigt habe, nicht durchlaufen werden können, aber das geht niemals darüber hinaus. Ist das wirklich das einzige, was du nicht tun kannst?

21
SeaNick

In Java/Android wird eine Variable oder Konstante static nicht gesammelt. Es bleibt nur dort, wenn die Klasse, die es enthält, über einen Klassenlader geladen wird. Der Klassenlader ist für alle Klassen in Ihrer App afaik immer derselbe und derjenige, der statische Verweise auf alle Ihre Klassen enthält (z. B. MyInnerClass.class). Da der Klassenlader nicht verschwindet, werden Ihre Klassen dies auch nicht tun, da sie referenziert werden und daher nicht als Müll gesammelt werden können.

Wie in deinem Beispiel

public class SomeClass extends SurfaceView {
  private static Context myContext;

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

Das ist in der Tat schlecht. Auch wenn kein Verweis auf SomeClass vorhanden ist (z. B. der Activity, der Ihre benutzerdefinierte SurfaceView beendet hat), ist der statische Verweis auf Context (und ein beliebiger anderer static Variable/Konstante in SomeClass bleibt erhalten Sie können alle durchgesickert betrachten, da es nicht möglich ist, das Context usw. zu sammeln. Wenn Sie eine reguläre Variable haben, verweisen Sie auf etwas, dann einmal die Instanz, die das enthält Variable hat keine weiteren Verweise darauf, die gesamte Instanz einschließlich der Verweise auf andere Dinge kann und wird gesammelt, Java kann sogar mit Zirkelverweisen umgehen.

Für Konstanten möchten Sie, dass dies geschieht, und es ist normalerweise nicht schlecht, da die Anzahl der Konstanten und der Speicher, den sie belegen, nicht groß ist. Konstanten verweisen (sollten nicht) auch auf andere Instanzen, die viel Speicherplatz beanspruchen, wie Context oder Bitmap.

Abgesehen von der Möglichkeit, Speicherverluste durch statische Variablen zu erzeugen, können Sie auch Probleme verursachen, wenn Sie nicht nur eine einzige Sache für alle Instanzen gleichzeitig haben möchten. Wenn Sie beispielsweise das Bitmap von SurfaceView in einer static -Variable speichern, können Sie nicht zwei verschiedene Bilder haben. Selbst wenn die beiden SurfaceViews nicht gleichzeitig angezeigt werden, können Probleme auftreten, da bei jeder neuen Instanz das alte Bild wahrscheinlich überschrieben wird und wenn Sie zum anderen SurfaceView zurückkehren, das unerwartete Bild unerwartet angezeigt wird . Ich bin fast sicher, dass Sie static hier nicht verwenden möchten.

Die Tatsache, dass Ihre innere Klasse ein static class ist, bedeutet nicht, dass Sie statische Variablen verwenden müssen - das bedeutet nur, dass sie sich eher wie eine static - Methode verhält, da sie die Instanzvariablen (die nicht sind) verwenden können static) in Ihrer Klasse.

Um Speicherverluste zu vermeiden, sollten Sie einfach keine statischen Variablen verwenden. Sie müssen nicht verwendet werden, es sei denn, Sie machen spezielle Dinge (z. B. das Zählen von Instanzen einer Klasse). Konstanten sind in Ordnung.

32
zapl

In diesem Artikel werden veränderbare statische Felder beschrieben: http://javabook.compuware.com/content/memory/problem-patterns/memory-leaks.aspx . Vermeiden Sie sie grundsätzlich und verwenden Sie stattdessen Konstanten.

0
IgorGanapolsky