Android: statyczne pola i wycieki pamięci

Studiowałem najlepsze praktyki zapobiegania wyciekom pamięci kontekstu/aktywności podczas tworzenia widoków i nie mogę znaleźć konkretnej odpowiedzi na to, co jest lub nie jest dozwolone, jeśli chodzi o pola statyczne w klasach.

Załóżmy, że mam kod tej postaci:

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

Jestem nieco zdezorientowany co do tego, co JVM faktycznie uważa za ClassLoader dla MyInnerClass. Technicznie, ponieważ jest to obiekt SurfaceView, wydaje się, że zmienne statyczne powinny istnieć zawsze raz aplikacja utworzyła instancję MyInnerClass jeden raz( co dzieje się, gdy widok jest najpierw napompowany), a następnie pozostaje tam do momentu zakończenia samej aplikacji. Jeśli tak jest, co uniemożliwia otwarcie Bitmap i obiektów Canvas i zapełnienie sterty?

Jedyne stwierdzenie, jakie widzę powtarzane w kółko, to to, że nie można wyciekać statycznego kontekstu, jak pokazałem w konstruktorze, ale nigdy nie wykracza poza to. Czy to naprawdę jedyna rzecz, której nie możesz zrobić?

Author: SeaNick, 2012-08-10

2 answers

W Javie/Android zmienna lub stała static nie będą zbierane śmieci. Po prostu pozostaje tam, gdy klasa, która go trzyma, zostanie załadowana za pomocą ładowarki klasowej. Class loader jest zawsze taki sam dla wszystkich klas w Twojej aplikacji i to ten, który ma statyczne odniesienia do wszystkich klas (do np. MyInnerClass.class). Ponieważ class loader nie odejdzie, Twoje klasy również tego nie zrobią, ponieważ są odwołane i dlatego nie można ich zbierać śmieci.

Jak w Twoim przykład

public class SomeClass extends SurfaceView {
  private static Context myContext;

  public MyInnerClass(Context context){
     myContext = context;        // This is bad.
  }
}
To naprawdę źle. Nawet jeśli nie istnieje żadne odniesienie do SomeClass (np. Activity, które pokazało, że twój zwyczaj SurfaceView się skończył), statyczne odniesienie do Context (i każda inna static zmienna / stała w SomeClass pozostanie. Można rozważyć wszystkie z nich wyciekły, ponieważ nie jest możliwe, aby śmieci zbierać, że Context itp. Jeśli masz regularną zmienną reference something to gdy instancja, która zawiera tę zmienną nie ma więcej referencji do niej cała instancja łącznie z jej odniesienia do innych rzeczy mogą i będą zbierane śmieci. Java może nawet dobrze obsługiwać odniesienia okrągłe.

Dla stałych chcesz, aby tak się stało i zwykle nie jest to złe, ponieważ ilość stałych i ilość pamięci, którą zajmują, nie jest duża. Również stałe nie powinny (nie powinny) odwoływać się do innych instancji, które zajmują duże ilości pamięci, takich jak Context lub Bitmap.

Oprócz możliwości tworzenia wycieków pamięci przez zmienne statyczne można również tworzyć problemy, jeśli nie chcesz mieć tylko jednej rzeczy dla wszystkich instancji w tym samym czasie. Na przykład, jeśli zapiszesz Bitmap swojego SurfaceView W Zmiennej static, nie możesz mieć dwóch różnych obrazów. Nawet jeśli dwa SurfaceViewnie są wyświetlane w tym samym czasie, możesz napotkać problemy, ponieważ każda nowa instancja prawdopodobnie nadpisze stary obraz, a jeśli wrócisz do drugiego SurfaceView nieoczekiwanie pokażesz niewłaściwy obraz. Jestem prawie pewien, że nie chcesz używać static tutaj.

Fakt to, że twoja wewnętrzna klasa jest static class nie oznacza, że musisz używać zmiennych statycznych - po prostu oznacza, że zachowuje się bardziej jak Metoda static, ponieważ nie może używać zmiennych instancji (tych, które nie są static) w twojej klasie.

Aby uniknąć wycieków pamięci, po prostu nie należy w ogóle używać zmiennych statycznych. Nie ma potrzeby ich używać, chyba że robisz specjalne rzeczy (np. zliczanie instancji klasy). Stałe są w porządku.

 31
Author: zapl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-17 10:26:54

Ten artykuł mówi o zmiennych polach statycznych: http://javabook.compuware.com/content/memory/problem-patterns/memory-leaks.aspx . zasadniczo unikaj ich i używaj stałych.

 0
Author: Igor Ganapolsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-19 18:50:30