152 votes

Quels outils Android et les méthodes fonctionnent le mieux pour trouver la ressource/mémoire fuites ?

J'ai une application Android développée, et j'en suis au point d'une application de téléphone de développement où tout semble bien fonctionner et que vous souhaitez déclarer la victoire et le bateau, mais vous savez, il suffit d'être un peu de mémoire et de ressources de fuites de là; et il y a seulement 16 mo de mémoire sur le système Android et de son apparemment, il est étonnamment facile de fuite dans une application Android.

J'ai été en regardant autour et jusqu'à présent, n'ont été en mesure de creuser l'info sur "hprof" et "traceview" et ni reçoit beaucoup de critiques favorables.

Quels sont les outils ou les méthodes avez-vous rencontré ou développés et de soins à part peut-être dans un projet OS?

90voto

hp.android Points 2201

L'une des erreurs les plus communes que j'ai trouvé développement d'Applications Android est la java.lang.OutOfMemoryError: Bitmap Taille Dépasse VM Budget d'erreur". J'ai trouvé cette erreur fréquemment sur les activités à l'aide de beaucoup d'images après le changement d'orientation: l'Activité est détruite, la création et les mises en page sont "gonflés" dans le XML de la consommation de la mémoire virtuelle disponible pour les bitmaps.

Images sur l'activité précédente disposition ne sont pas correctement libéré par le garbage collector parce qu'ils ont des références croisées à leur activité. Après de nombreuses expériences, j'ai trouvé une très bonne solution pour ce problème.

Tout d'abord, définissez l'attribut "id" sur la vue parent de votre mise en page 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, sur le onDestroy() la méthode de votre Activité, appelez le unbindDrawables() la méthode passage d'une référence à la Vue parent et ensuite faire un Système.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 unbindDrawables() la méthode explore le point de vue de l'arbre de manière récursive et:

  1. Supprime rappels sur tout l'arrière-plan un drawable
  2. Supprime childs sur chaque viewgroup

29voto

28voto

Timo Ohr Points 5550

Surtout pour les voyageurs de Google du futur :

La plupart des outils java ne conviennent pas malheureusement pour cette tâche, car ils n’analysent le tas de la JVM. Chaque Application Android a aussi un tas natif, cependant, qui a aussi pour s’intégrer dans la limite de ~ 16 Mo. Il est généralement utilisé pour les données de bitmap, par exemple. Si vous pouvez exécuter assez facilement dans les erreurs de mémoire même si votre tas JVM est chillin autour de 3 Mo, si vous utilisez beaucoup de drawables.

20voto

darrenp Points 872

La réponse de @hp.android fonctionne bien si vous êtes simplement de travailler avec bitmap horizons, mais, dans mon cas, j'ai eu un BaseAdapter proposant un ensemble d' ImageViews pour GridView. J'ai modifié l' unbindDrawables() méthode comme conseillé, de sorte que la condition est:

if (view instanceof ViewGroup && !(view instanceof AdapterView)) {
  ...
}

mais le problème est alors que la méthode récursive jamais traite les enfants de l' AdapterView. Pour répondre à cela, j'ai plutôt fait le suivant:

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 l' AdapterView sont encore traités -- la méthode juste ne pas essayer d'enlever tous les enfants (qui n'est pas pris en charge).

Ce n'est pas tout à fait corriger le problème, toutefois, depuis ImageViews gérer une image qui n'est pas de leur arrière-plan. J'ai donc ajouté ce qui suit. Ce n'est pas l'idéal, mais ça fonctionne:

if (view instanceof ImageView) {
  ImageView imageView = (ImageView) view;
  imageView.setImageBitmap(null);
}

Dans l'ensemble, l' unbindDrawables() méthode 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 y a une plus approche fondée sur des principes pour libérer ces ressources.

12voto

greg7gkb Points 1625

Bon Google i/o parler (2011) sur la gestion de la mémoire dans Android, ainsi que des détails sur les outils + techniques pour le profilage de la mémoire :
http://www.youtube.com/watch?v=_CruQY55HOk

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X