Android: campos estáticos y memory leaks

He estado estudiando las mejores prácticas para evitar memory leaks de contexto / actividad al crear vistas, y parece que no puedo encontrar una respuesta definitiva sobre lo que está permitido o no cuando se trata de campos estáticos en las clases.

Digamos que tengo un código de esta forma:

public class MyOuterClass extends Activity{ private MyInnerClass; MyInnerClass = (MyInnerClass) findViewById(); 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. } } } 

Estoy un poco confundido sobre lo que la JVM realmente considera el ClassLoader para MyInnerClass. Técnicamente, dado que es un objeto SurfaceView, parece que las variables estáticas siempre deben existir una vez que la aplicación ha instanciado MyInnerClass una vez (lo que sucede cuando la vista se infló por primera vez), y luego permanecer allí hasta que la aplicación se termine. Si ese es el caso, ¿qué impide que los objetos Bitmaps y Canvas permanezcan abiertos y llenen el montón?

La única afirmación que veo repetida una y otra vez es que no se puede filtrar el contexto estático como lo he mostrado en el constructor, pero nunca va más allá. ¿Es eso realmente lo único que no puedes hacer?

En Java / Android, una variable static o constante no será basura recolectada. Simplemente permanece allí una vez que la clase que lo contiene se carga a través de un cargador de clases. El cargador de clases es afaik siempre el mismo para todas las clases dentro de su aplicación y es el que tiene referencias estáticas a todas sus clases (por ejemplo, MyInnerClass.class ). Como el cargador de clases no desaparece, tus clases tampoco lo harán, ya que están referenciadas y, por lo tanto, no son recolectables.

Como en tu ejemplo

 public class SomeClass extends SurfaceView { private static Context myContext; public MyInnerClass(Context context){ myContext = context; // This is bad. } } 

Eso es realmente malo. Incluso si no existe ninguna referencia a SomeClass (por ejemplo, la Activity que mostró que su SurfaceView personalizado ha finalizado) la referencia estática al Context (y cualquier otra variable static / constante en SomeClass se mantendrá. Puede considerar todas ellas filtradas ya que no es posible recolectar ese Context etc. Si tiene una variable regular, haga referencia a algo, una vez que la instancia que contiene esa variable ya no tenga más referencias, toda la instancia, incluidas sus referencias a otras cosas, puede ser recolectada. referencias bien

Para las constantes, quiere que eso suceda y, en general, no está mal, ya que la cantidad de constantes y la cantidad de memoria que ocupan no es grande. Además, las constantes no hacen referencia (no deberían) a otras instancias que ocupan grandes cantidades de memoria, como Context o Bitmap .

Además de la posibilidad de crear pérdidas de memoria a través de variables estáticas, también puede crear problemas si no desea tener una sola cosa para todas las instancias al mismo tiempo. Por ejemplo, si guarda el Bitmap de Bitmap de su SurfaceView en una variable static , no puede tener dos imágenes diferentes. Incluso si los dos SurfaceView s no se muestran al mismo tiempo, podría tener problemas ya que cada nueva instancia probablemente sobrescribirá la imagen anterior y si vuelve al otro SurfaceView , inesperadamente mostrará la imagen incorrecta. Estoy casi seguro de que no quieres usar static aquí.

El hecho de que su clase interna sea una static class no significa que tenga que usar variables estáticas; simplemente significa que se comporta más como un método static ya que no puede usar las variables de instancia (las que no son static ) en Tu clase.

Para evitar memory leaks, simplemente no debe usar variables estáticas en absoluto. No hay necesidad de usarlos a menos que haga cosas especiales (por ejemplo, contar instancias de una clase). Las constantes están bien.

Este artículo habla sobre campos estáticos mutables: http://javabook.compuware.com/content/memory/problem-patterns/memory-leaks.aspx . Básicamente, evítelos y use constantes en su lugar.