J'ai étudié les meilleures pratiques pour éviter les fuites de mémoire de contexte/activité lors de la création de vues, et je n'arrive pas à trouver de réponse définitive à ce qui est autorisé ou non par rapport aux champs statiques dans les classes.
Disons que j'ai un code de cette forme:
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.
}
}
}
Je suis un peu confus sur ce que la machine virtuelle Java considère réellement comme le ClassLoader pour MyInnerClass. Techniquement, puisqu'il s'agit d'un objet SurfaceView, il semble que les variables statiques devraient toujours exister une fois que l'application a instancié MyInnerClass une fois (ce qui se produit lorsque la vue est gonflée pour la première fois), puis y rester jusqu'à ce que l'application elle-même se termine. Si tel est le cas, qu'est-ce qui empêche les objets Bitmaps et Canvas de rester ouverts et de remplir le tas?
La seule affirmation que je vois se répéter encore et encore est qu'il est impossible de filtrer le contexte statique comme je l'ai montré dans le constructeur, mais cela ne va jamais au-delà. Est-ce vraiment la seule chose que vous ne pouvez pas faire?
En Java/Android, une variable ou une constante static
ne sera pas récupérée. Il y reste simplement une fois que la classe qui la détient est chargée via un chargeur de classes. Le chargeur de classe est toujours le même pour toutes les classes de votre application et c'est celui qui contient des références statiques à toutes vos classes (par exemple, MyInnerClass.class
). Puisque le chargeur de classes ne s'en va pas, vos classes ne le feront pas non plus, car elles sont référencées et ne peuvent donc pas être récupérées.
Comme dans votre exemple
public class SomeClass extends SurfaceView {
private static Context myContext;
public MyInnerClass(Context context){
myContext = context; // This is bad.
}
}
C'est vraiment mauvais. Même si aucune référence à SomeClass
n'existe (par exemple, la Activity
qui a montré que votre SurfaceView
est terminée), la référence statique à la Context
(et toute autre variable static
/constante dans SomeClass
restera. Vous pouvez toutes les considérer comme fuites car ce n'est pas possible. garbage collect this Context
etc. Si vous avez une variable régulière référencée, alors une fois que l'instance contenant cette variable n'a plus de référence, l'instance entière, y compris ses références à d'autres éléments, peut et sera collectée. Java peut même gérer les données circulaires. références bien.
Pour les constantes, vous voulez que cela se produise et ce n’est généralement pas mauvais, car la quantité de constantes et la quantité de mémoire qu’elles occupent ne sont pas grandes. De plus, les constantes ne font pas (ne devraient pas) faire référence à d'autres instances qui utilisent de grandes quantités de mémoire, comme Context
ou Bitmap
.
Outre la possibilité de créer des fuites de mémoire via des variables statiques, vous pouvez également créer des problèmes si vous ne voulez pas avoir une seule chose pour toutes les instances en même temps. Par exemple, si vous enregistrez la Bitmap
de votre SurfaceView
dans une variable static
, vous ne pouvez pas avoir deux images différentes. Même si les deux variables SurfaceView
s ne sont pas affichées en même temps, des problèmes risquent de se produire, car chaque nouvelle instance écrasera probablement l'ancienne image. Si vous revenez à l'autre SurfaceView
, vous affichez de manière inattendue la mauvaise image. Je suis presque sûr que vous ne voulez pas utiliser static
ici.
Le fait que votre classe interne soit un static class
ne signifie pas que vous devez utiliser des variables statiques - cela signifie simplement qu'elle se comporte davantage comme une méthode static
car elle ne peut pas utiliser les variables d'instance (celles qui ne sont pas static
) classe.
Pour éviter les fuites de mémoire, vous ne devez absolument pas utiliser de variables statiques. Il n’est pas nécessaire de les utiliser à moins d’effectuer des tâches spéciales (par exemple, compter des instances d’une classe). Les constantes vont bien.
Cet article parle de champs statiques mutables: http://javabook.compuware.com/content/memory/problem-patterns/memory-leaks.aspx . En gros, évitez-les et utilisez plutôt des constantes.