14

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 une réponse définitive à ce qui est autorisé ou non. arrive aux champs statiques dans les classes.Android: champs statiques et fuites de mémoire

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 en fait 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 arrive lorsque la vue est gonflée), et y rester jusqu'à ce que l'application soit terminée. 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 déclaration que je vois encore et encore est que vous ne pouvez pas fuir 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?

+0

votre 'Canvas' etc. n'a pas besoin d'être' static'. De cette façon il resterait en effet dans le tas pour toujours – zapl

+1

Si tel est le cas alors qu'est-ce qui empêche les constantes (c'est-à-dire - private static final int MY_CONSTANT), de tenir aussi n'importe quelle classe qui étend l'activité (et son contexte) ouverte? – SeaNick

Répondre

27

En Java/Android, une variable static ou constante ne sera pas collectée. Il reste juste là une fois que la classe qui le contient est chargée via un chargeur de classe. Le chargeur de classe est toujours le même pour toutes les classes de votre application et celui qui a des références statiques à toutes vos classes (par exemple MyInnerClass.class). Puisque le chargeur de classes ne disparaît pas, vos classes ne le feront pas non plus puisqu'elles sont référencées & donc ne peuvent pas être collecté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 en effet mauvais. Même si aucune référence à SomeClass n'existe (par exemple le Activity qui a montré votre SurfaceView personnalisé a pris fin) la référence statique à la Context (et toute autre variable/constante static dans SomeClass resteront.) Vous pouvez les considérer tous fuite parce que ce n'est pas possible Si vous avez une variable de référence régulière quelque chose, alors une fois que l'instance qui contient cette variable n'a plus de références à l'ensemble de l'instance, y compris ses références à d'autres choses peuvent et seront recueillies garbage.Java peut même gérer circulaire

Pour les constantes que vous voulez que cela se produise et il est généralement pas mal car la quantité de constantes et la quantité de mémoire qu'ils occupent n'est pas grande.) référence d'autres instances qui occupent de grandes quantités de mémoire, telles que Context ou Bitmap. En plus de 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 le Bitmap de votre SurfaceView dans une variable static, vous ne pouvez pas avoir deux images différentes. Même si les deux SurfaceView ne s'affichent pas en même temps, vous risquez de rencontrer des problèmes car chaque nouvelle instance remplacera probablement l'ancienne image et si vous revenez à l'autre SurfaceView, vous affichez la mauvaise image de manière inattendue. Je suis presque sûr que vous ne voulez pas utiliser static ici. Le fait que votre classe interne soit static class ne signifie pas que vous devez utiliser des variables statiques - cela signifie simplement qu'il se comporte davantage comme une méthode static puisqu'il ne peut pas utiliser les variables d'instance (celles qui ne le sont pas). static) dans votre cours.

Pour éviter les fuites de mémoire, vous ne devriez tout simplement pas utiliser de variables statiques. Il n'est pas nécessaire de les utiliser à moins de faire des choses spéciales (par exemple, compter des instances d'une classe). Les constantes vont bien.

+0

Merci. Je suppose que le raisonnement général pour vouloir la statique était parce que conceptuellement, la plupart des objets View n'ont besoin que d'une seule instance, puisqu'ils représentent généralement un écran ou un objet spécifique à l'écran. Le code semble beaucoup plus efficace pour les rendre statiques, mais je comprends l'inconvénient. La seule chose qui me dérange à propos de laisser les variables à la merci totale du GC est que je n'ai aucun contrôle sur quand il aura besoin de libérer de la mémoire, et de tout ce que j'ai vu dans mon application, c'est toujours pendant une opération bitmap, dont j'ai peur va se transformer en taux de trame nerveux. – SeaNick

+1

Vous n'avez pas besoin d'avoir quelque chose de statique pour le garder en vie et le réutiliser. Il existera aussi longtemps que vous avez une référence à celui-ci. Et l'utilisation de la statique conduira généralement à plus de consommation de mémoire si vous oubliez de «null» toutes vos références statiques de manière appropriée. + Les instances de vue seront généralement recréées si vous faites pivoter l'écran par exemple – zapl

+1

Je garde l'orientation de l'écran verrouillée, mais c'est un très bon point. Merci encore! – SeaNick