14

Ja studiuje się na temat najlepszych praktyk w celu zapobiegania pamięć Kontekst/Activity przecieków podczas tworzenia widoków, a ja nie mogę znaleźć jednoznacznej odpowiedzi na to, co jest lub nie jest dozwolone, gdy przychodzi do pól statycznych na zajęciach.Android: statycznych pól i Memory Wycieki

Powiedzmy mam kod 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 mylić na co JVM faktycznie uważa classloader dla MyInnerClass. Z technicznego punktu widzenia, ponieważ jest to obiekt SurfaceView, wydaje się, że zmienne statyczne powinny zawsze istnieć, gdy aplikacja stworzy instancję MyInnerClass jeden raz (co dzieje się, gdy widok jest najpierw zawyżony), a następnie pozostaje tam, dopóki sama aplikacja nie zostanie zakończona. Jeśli tak, to co zapobiega również otwarciu map bitmapowych i obiektów Canvas i wypełnieniu sterty?

Jedyne oświadczenie kiedykolwiek zobaczyć powtarzane w kółko, jest to, że nie może przeciekać Kontekst statyczne jak wykazałem w konstruktorze, ale nigdy nie wykracza poza to. Czy to naprawdę jedyna rzecz, której nie możesz zrobić?

+0

twoje "płótno" itp. Nie musi być "statyczne". W ten sposób rzeczywiście pozostanie na kupce na zawsze – zapl

+1

Jeśli tak jest, to co zapobiega stałym (tj. - prywatnemu statycznemu finałowi MY MYCONSTANT), czy też zawiera dowolną klasę, która rozszerza aktywność (i jej kontekst)? – SeaNick

Odpowiedz

27

W Java/Android static zmienny lub stały śmieci nie będą zbierane. Pozostaje tam tylko wtedy, gdy klasa, która go zatrzymuje, jest ładowana przez moduł ładujący klasy. Program ładujący klasy jest zawsze taki sam dla wszystkich klas w Twojej aplikacji i ten, który ma statyczne odwołania do wszystkich twoich klas (na przykład MyInnerClass.class). Ponieważ program ładujący klasy nie zniknie, twoje klasy też tego nie zrobią, ponieważ są one przywoływane jako &, a zatem nie są zbiorem śmieci.

Podobnie jak w przykładzie

public class SomeClass extends SurfaceView { 
    private static Context myContext; 

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

To jest rzeczywiście źle. Nawet jeśli nie ma odniesienia do SomeClass (np. Activity, który pokazał, że Twój niestandardowy SurfaceView został zakończony), pozostanie statyczne odwołanie do Context (i dowolnej innej zmiennej/stałejw SomeClass. Możesz uznać, że wszystkie z nich wyciekły, ponieważ nie jest to możliwe naśmiewać, że Context itd. Jeśli masz regularną zmienną odwołanie coś, a następnie raz wystąpienie, które zawiera tę zmienną nie ma więcej odwołań do niej całej instancji, w tym jej odniesienia do innych rzeczy mogą i będą śmieci zbierane. referencje dobrze

Dla stałych chcesz, aby tak się stało i zwykle nie jest źle, ponieważ ilość stałych i ilość zajmowanej przez nie pamięci nie jest duża. Również stałe nie (nie powinny) odnoszą się do innych instancji, które zajmują duże ilości pamięci, takie jak Context lub Bitmap.

Poza możliwością tworzenia pamięci przecieki przez zmiennych statycznych może również powodować problemy, jeśli nie chcemy mieć tylko jedną rzecz dla wszystkich instancji w tym samym czasie. Na przykład, jeśli zapiszesz Bitmap swojej zmiennej SurfaceView w zmiennej static, nie możesz mieć dwóch różnych obrazów. Nawet jeśli oba te SurfaceView s nie są wyświetlane w tym samym czasie, możesz napotkać problemy, ponieważ każda nowa instancja prawdopodobnie nadpisze stary obraz i jeśli wrócisz do innego SurfaceView, niespodziewanie wyświetlisz zły obraz. Jestem prawie pewien, że nie chcesz używać tutaj static.

Fakt, że twoja wewnętrzna klasa to static class nie oznacza, że ​​musisz używać zmiennych statycznych - to 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ąć przecieków pamięci po prostu nie należy używać zmiennych statycznych w ogóle. Nie ma potrzeby korzystania z nich, chyba że zrobisz coś specjalnego (np. Zliczanie instancji klasy). Stałe są w porządku.

+0

Dzięki. Sądzę, że ogólne uzasadnienie dla posiadania statyki było, ponieważ koncepcyjnie, większość obiektów View tylko potrzebuje jednej instancji, ponieważ zazwyczaj reprezentują one określony ekran lub obiekt na ekranie. Wydaje się, że ich kodowanie jest znacznie bardziej wydajne pod względem kodowania, ale rozumiem tutaj jego wadę. Jedyną rzeczą, która mi przeszkadza pozostawiając zmienne w całkowitej łasce GC, jest to, że nie mam kontroli nad tym, kiedy będzie trzeba zwolnić pamięć, a ze wszystkiego, co widziałem w mojej aplikacji, zawsze jest to podczas operacji bitmapowej, Obawiam się, że zmieni się w niestabilne liczby klatek na sekundę. – SeaNick

+1

Nie musisz mieć czegoś statycznego, aby utrzymać go przy życiu i użyć go ponownie. Będzie istnieć tak długo, jak będziesz miał do tego odniesienie. Używanie statycznego zazwyczaj prowadzi do większego zużycia pamięci, jeśli zapomnisz "null" wszystkie twoje statyczne odniesienia. + Wyświetl instancje będą zazwyczaj odtwarzane, jeśli obrócisz ekran, na przykład – zapl

+1

Utrzymuję orientację ekranu zamkniętą, ale to bardzo dobry punkt. Dzięki jeszcze raz! – SeaNick

Powiązane problemy