J'ai une Android développée) et je suis sur le point de développer une application pour téléphone où tout semble bien fonctionner et où vous souhaitez déclarer victoire et livraison, mais vous savez qu'il existe Il ne reste plus que quelques fuites de mémoire et de ressources; et il n’ya que 16 Mo de tas sur le Android et il est apparemment étonnamment facile de fuir dans un Android app .
J'ai jeté un coup d'œil autour de moi et, jusqu'à présent, je n'ai pu que creuser des informations sur "hprof" et "traceview", sans obtenir de nombreuses critiques favorables.
Quels outils ou méthodes avez-vous rencontrés ou développés et souhaitez-vous partager dans un projet de système d'exploitation?
L'une des erreurs les plus courantes que j'ai constatées lors du développement Android Apps est l'erreur "Java.lang.OutOfMemoryError: la taille du bitmap dépasse la valeur VM Budget"). J'ai trouvé ceci. erreur fréquemment sur les activités utilisant beaucoup de bitmaps après avoir changé d'orientation: l'activité est détruite, créée à nouveau et les mises en page sont "gonflées" à partir du XML qui utilise la mémoire VM disponible pour les bitmaps.
Les bitmaps de la structure d'activité précédente ne sont pas correctement désalloués par le ramasse-miettes car ils ont croisé les références à leur activité. Après de nombreuses expériences, j'ai trouvé une très bonne solution à ce problème.
Tout d’abord, définissez l’attribut "id" sur la vue parent de votre présentation XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="fill_parent"
Android:layout_height="fill_parent"
Android:id="@+id/RootView"
>
...
Ensuite, dans la méthode onDestroy () de votre activité, appelez la méthode unbindDrawables () en transmettant une référence à la vue parent, puis effectuez System.gc ().
@Override
protected void onDestroy() {
super.onDestroy();
unbindDrawables(findViewById(R.id.RootView));
System.gc();
}
private void unbindDrawables(View view) {
if (view.getBackground() != null) {
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
((ViewGroup) view).removeAllViews();
}
}
Cette méthode unbindDrawables () explore l'arborescence de la vue de manière récursive et:
Procurez-vous l'analyseur de mémoire Eclipse ( http://www.Eclipse.org/mat/ ) à vérifier http://kohlerm.blogspot.com/2010/02/Android-memory-usage -analysis-slides.html et http://kohlerm.blogspot.com/search/label/memory
Principalement pour les voyageurs Google de l'avenir:
La plupart des Java ne conviennent malheureusement pas à cette tâche, car ils analysent uniquement le tas JVM. Chaque Android Application possède également un segment de mémoire natif, qui doit respecter la limite de ~ 16 Mo. Il est généralement utilisé pour les données bitmap, par exemple, ce qui vous permet de facilement échapper aux erreurs Out Of Memory même si votre machine virtuelle JVM-Heap tourne autour de 3 Mo si vous utilisez beaucoup de fonctions dessinables. .
La réponse de @ hp.Android fonctionne bien si vous travaillez uniquement avec des arrière-plans bitmap mais, dans mon cas, j’avais un BaseAdapter
fournissant un ensemble de ImageView
s pour un GridView
. J'ai modifié la méthode unbindDrawables()
comme indiqué afin que la condition soit:
if (view instanceof ViewGroup && !(view instanceof AdapterView)) {
...
}
mais le problème est alors que la méthode récursive ne traite jamais les enfants du AdapterView
. Pour remédier à cela, j'ai plutôt fait ce qui suit:
if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
for (int i = 0; i < viewGroup.getChildCount(); i++)
unbindDrawables(viewGroup.getChildAt(i));
if (!(view instanceof AdapterView))
viewGroup.removeAllViews();
}
afin que les enfants de AdapterView
soient toujours traités - la méthode ne tente tout simplement pas de supprimer tous les enfants (ce qui n'est pas pris en charge).
Cela ne résout toutefois pas le problème puisque ImageView
s gère un bitmap qui n’est pas leur arrière-plan. J'ai donc ajouté ce qui suit. Ce n'est pas idéal mais ça marche:
if (view instanceof ImageView) {
ImageView imageView = (ImageView) view;
imageView.setImageBitmap(null);
}
Globalement, la méthode unbindDrawables()
est alors:
private void unbindDrawables(View view) {
if (view.getBackground() != null)
view.getBackground().setCallback(null);
if (view instanceof ImageView) {
ImageView imageView = (ImageView) view;
imageView.setImageBitmap(null);
} else if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
for (int i = 0; i < viewGroup.getChildCount(); i++)
unbindDrawables(viewGroup.getChildAt(i));
if (!(view instanceof AdapterView))
viewGroup.removeAllViews();
}
}
J'espère qu'il existe une approche plus fondée sur des principes pour libérer de telles ressources.
Bonne conversation Google I/O (2011) sur la gestion de la mémoire dans Android, ainsi que des détails sur les outils et les techniques de profilage de la mémoire:
http://www.youtube.com/watch?v=_CruQY55HOk
Valgrind a été porté sur Android (sponsorisé par Mozilla). Voir Valgrind sur Android - État actuel) et Support Exécuter Valgrind pour Android sur ARM (commentaire 67).
Eh bien, ce sont les outils qui se rattachent aux formats uniques que Android utilise ...
Avez-vous essayé de simuler des zones de code à l’aide du framework Android Mock?