Quand est-il exactement de fuite sûr à utiliser (anonyme) intérieur classes?
J'ai lu quelques articles sur les fuites de mémoire dans Android et regardé cette vidéo intéressante de Google I/O sur le sujet.
Encore, je ne comprends pas tout le concept, et surtout quand il est sûr ou dangereux pour l'utilisateur intérieur des classes à l'intérieur d'une Activité.
C'est ce que j'ai compris:
Une fuite de mémoire se produit si une instance d'un intérieur de classe survit plus que de l'extérieur de la classe (une Activité).
-> Dans quelles situations peut-il se passer?
Dans cet exemple, je suppose qu'il n'y a pas de risque de fuite, car il n'existe aucun moyen de la classe anonyme extension OnClickListener
vivent plus longtemps que l'activité, à droite?
final Dialog dialog = new Dialog(this);
dialog.setContentView(R.layout.dialog_generic);
Button okButton = (Button) dialog.findViewById(R.id.dialog_button_ok);
TextView titleTv = (TextView) dialog.findViewById(R.id.dialog_generic_title);
//*** Handle button click
okButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
dialog.dismiss();
}
});
titleTv.setText("dialog title");
dialog.show();
Maintenant, est-ce un exemple dangereux, et pourquoi?
//We are still inside an Activity
_handlerToDelayDroidMove = new Handler();
_handlerToDelayDroidMove.postDelayed(_droidPlayRunnable, 10000);
private Runnable _droidPlayRunnable = new Runnable() {
public void run() {
_someFieldOfTheActivity.performLongCalculation();
}
};
J'ai un doute sur le fait que la compréhension de ce sujet a à voir avec la compréhension en détail ce qui est maintenu lorsqu'une activité est détruit et recréé.
Est-il?
Disons que j'ai juste changé l'orientation de l'appareil (ce qui est la cause la plus fréquente de fuites). Lorsque super.onCreate(savedInstanceState)
sera appelé dans mon onCreate()
, cette rétablir les valeurs des champs comme ils l'étaient avant le changement d'orientation)? Est-ce aussi restaurer les états de classes internes?
Je me rends compte que ma question n'est pas très précis, mais j'aimerais vraiment apprécier toute explication qui pourrait rendre les choses plus claires.
Vous devez vous connecter pour publier un commentaire.
Ce que vous demandez est une jolie question difficile. Alors que vous pouvez penser que c'est juste une question, vous êtes en train de demander plusieurs questions à la fois. Je vais faire de mon mieux avec les connaissances que j'ai de le couvrir et, nous l'espérons, d'autres vont se joindre à couvrir ce que je peut manquer.
Classes Imbriquées: Introduction
Que je ne suis pas sûr de la façon dont vous êtes à l'aise avec la programmation orientée objet en Java, ce sera frappé un couple de notions de base. Une classe imbriquée est lors de la définition d'une classe est contenue dans une autre classe. Il existe essentiellement deux types: Statique Classes Imbriquées et les Classes internes. La vraie différence entre ces sont:
La Collecte des ordures et les Classes internes
La Collecte des ordures est automatique, mais essaie de supprimer des objets en se basant sur le fait qu'elle pense qu'ils sont utilisés. Le Garbage Collector est assez intelligent, mais pas sans faille. Il ne peut déterminer si quelque chose est utilisé par de si oui ou non il y a un actif de référence à l'objet.
Le vrai problème ici, c'est quand un intérieur de classe a été maintenu en vie plus longtemps que son conteneur. C'est à cause de la référence implicite à la classe conteneur. La seule manière dont cela peut se produire si un objet en dehors de la classe conteneur conserve une référence à l'objet interne, sans égard à l'objet contenant.
Cela peut conduire à une situation où l'objet interne est vivant (par référence), mais les références à l'objet contenant a déjà été retiré de tous les autres objets. L'objet interne est, par conséquent, le maintien de l'objet contenant en vie parce qu'il va toujours avoir une référence. Le problème, c'est que si il est programmé, il n'y a aucun moyen de revenir à l'objet contenant pour vérifier si il est encore vivant.
L'aspect le plus important de cette prise de conscience, c'est qu'il ne fait aucune différence si c'est dans une Activité ou un drawable. Vous toujours faut être précis lors de l'utilisation de classes internes et assurez-vous qu'ils ne jamais durer plus longtemps que les objets du conteneur. Heureusement, si ce n'est pas un objet de base de votre code, les fuites peuvent être de petite taille en comparaison. Malheureusement, ces sont parmi les plus difficiles fuites à trouver, parce qu'ils sont susceptibles de passer inaperçues jusqu'à ce que beaucoup d'entre eux ont fui.
Solutions: Les Classes Internes
Activités et points de Vue: Introduction
Activités contiennent beaucoup d'informations pour être en mesure d'exécuter et d'afficher. Les activités sont définies par les caractéristiques qu'ils doivent avoir un point de Vue. Ils ont aussi certaines automatique des gestionnaires. Si vous spécifiez ou non, l'Activité a une référence implicite à la Vue qu'il contient.
Pour une Vue à créer, il faut savoir où créer et s'il a des enfants afin de pouvoir l'afficher. Cela signifie que chaque point de Vue a une référence à l'Activité (via
getContext()
). En outre, toutes les vues garde des références à ses enfants (c'est à diregetChildAt()
). Enfin, chaque Vue conserve une référence à l'rendu Bitmap qui représente son affichage.Chaque fois que vous avez une référence à une Activité (ou Contexte d'Activité), ce qui signifie que vous pouvez suivre l'ENSEMBLE de la chaîne de la mise en page de la hiérarchie. C'est pourquoi les fuites de mémoire concernant les Activités ou les points de Vues sont comme une affaire énorme. Il peut être un tonne de la mémoire de la fuite de tous à la fois.
Les activités, les Opinions et les Classes internes
Donné les informations ci-dessus sur les Classes internes, ce sont les plus communs des fuites de mémoire, mais également le plus souvent à éviter. S'il est souhaitable d'avoir un intérieur de classe ont un accès direct à l'une des Activités les membres de la classe, beaucoup sont prêts à faire juste statique pour éviter d'éventuels problèmes. Le problème avec les Activités et les points de Vue va beaucoup plus loin que ça.
Fuite d'Activités, des Vues et de l'Activité des Contextes
Il s'agit du Contexte et de la Vie. Il y a certains événements (comme l'orientation) qui permet de tuer un Contexte d'Activité. Étant donné le nombre de classes et de méthodes nécessitent un Contexte, les développeurs essaient parfois pour enregistrer un code en le saisissant par une référence à un Contexte et de s'y accrocher. Il se trouve que beaucoup des objets que nous avons créer pour exécuter notre Activité d'exister en dehors de l'Activité du Cycle de vie afin de permettre à l'Activité de faire ce qu'il doit faire. Si l'un de vos objets ont une référence à une Activité, de son Contexte, ou l'un quelconque de ses points de Vue lorsqu'il est détruit, vous venez de fuite de l'Activité et de l'ensemble de son arborescence.
Solutions: les Activités et les points de Vue
getBaseContext()
ougetApplicationContext()
). Ces ne gardez pas les références implicitement.Runnables: Introduction
Runnables sont en fait pas si mal que ça. Je veux dire, ils pourrait être, mais nous avons déjà atteint la plupart des zones de danger. Un Exécutable est une opération asynchrone qui exécute une tâche indépendante de la thread qu'il a été créé. La plupart des runnables sont instanciés à partir de la thread de l'INTERFACE utilisateur. En essence, à l'aide d'un Exécutable est de créer un autre thread, juste un peu plus réussi. Si vous classe Exécutable, comme une norme de classe et de suivre les directives ci-dessus, vous devez exécuter dans quelques problème. La réalité est que beaucoup de développeurs ne pas le faire.
De la facilité, de la lisibilité et de la logique de déroulement du programme, de nombreux développeurs utilisent Anonyme Intérieur des Classes pour définir leur Runnables, comme dans l'exemple que vous créez ci-dessus. Il en résulte un exemple comme celui que vous avez tapé ci-dessus. Un Anonyme Intérieur de la Classe est en fait un discret Intérieur de la Classe. Vous n'avez pas à créer une toute nouvelle définition et simplement remplacer les méthodes appropriées. Dans tous les autres égards, il est un Intérieur de Classe, ce qui signifie qu'il conserve une référence implicite à son conteneur.
Runnables et Activités/Vues
Yay!!! Cette section peut être courte! En raison du fait que Runnables exécuté en dehors du thread courant, le danger avec ces d'une durée de l'exécution des opérations asynchrones. Si l'exécutable est défini dans une Activité ou de la Vue comme un Anonyme Intérieur de la Classe OU imbriqués à l'Intérieur de la Classe, il y a de très graves dangers. C'est parce que, comme mentionné précédemment, il a savoir qui de son récipient qu'en est. Entrez le changement d'orientation (ou système de tuer). Maintenant il suffit de se référer aux sections précédentes pour comprendre ce qui s'était passé. Oui, votre exemple est très dangereux.
Solutions: Runnables
Répondre à la dernière Question
Maintenant pour répondre à des questions qui n'ont pas directement adressée par les autres sections de ce post. Vous avez demandé "Quand est-ce un objet de l'un à l'intérieur de la classe de survivre plus longtemps que de l'extérieur de la classe?" Avant d'arriver à cela, permettez-moi d'insister: si vous avez raison de vous inquiéter à ce sujet dans les Activités, il peut provoquer une fuite de n'importe où. Je doit fournir un exemple simple (sans l'aide d'une Activité), simplement pour démontrer.
Ci-dessous est un exemple courant d'une base de l'usine (il manque le code).
Ce n'est pas comme l'exemple courant, mais assez simple à démontrer. La clé ici est le constructeur...
Maintenant, nous avons des Fuites, mais pas d'Usine. Même si nous avons sorti de l'Usine, il restera dans la mémoire, comme chaque Fuite a une référence à elle. Il n'est pas même question que l'extérieur de la classe n'a pas de données. Cela arrive bien plus souvent qu'on ne le pense. Nous n'avons pas besoin du créateur, juste ses créations. Nous avons donc créer temporairement, mais d'utiliser les créations à l'infini.
Imaginer ce qui se passe lorsque nous changeons le constructeur légèrement.
Maintenant, chacun de ces nouveaux LeakFactories a juste été divulgué. Que pensez-vous de cela? Ce sont deux très fréquents exemples de la façon dont un intérieur de classe peuvent survivre à l'extérieur de la classe de n'importe quel type. Si l'extérieur de la classe avait été une Activité, imaginez à quel point elle était pire.
Conclusion
Ces liste la plus connue des dangers de l'utilisation de ces objets de façon inappropriée. En général, ce poste doit avoir couvert la plupart de vos questions, mais je comprends que c'était un loooong post, donc si vous avez besoin de précisions, faites le moi savoir. Tant que vous suivez les pratiques ci-dessus, vous aurez très peu de souci de fuite.
AsyncTask
, mêmes problèmes que deRunnable
s'appliquerait. Suis-je la corriger?AsyncTask
est auto-géré (c'est à dire GC avais). Ainsi, elle évite la plupart des problèmes que mauvais usage deRunnable
. Autant que je sache, ça n'a pas changé.SwissCheese
exemple une fois qu'il a fait son travail, l'Usine sera en mesure d'être GCed, et la fuite de mémoire sera pas un problème plus longtemps, ai-je le droit?