Garbage collector sous Android

108

J'ai vu de nombreuses réponses Android suggérant d'appeler le garbage collector dans certaines situations.

Est-ce une bonne pratique de demander le ramasse-miettes dans Android avant d'effectuer une opération gourmande en mémoire? Sinon, dois-je l'appeler uniquement si j'obtiens une OutOfMemoryerreur?

Y a-t-il d'autres choses que je devrais utiliser avant de recourir au garbage collector?

hpique
la source

Réponses:

144

Pour les versions antérieures à 3.0 en nid d'abeille : Oui, appelez System.gc() .

J'ai essayé de créer des Bitmaps, mais j'obtenais toujours "Erreur de mémoire de la VM". Mais, quand j'ai appelé le System.gc()premier, ça allait.

Lors de la création de bitmaps, Android échoue souvent avec des erreurs de mémoire insuffisante et n'essaye pas de procéder au ramassage des ordures en premier . Par conséquent, appelez System.gc()et vous avez suffisamment de mémoire pour créer des bitmaps.

Si vous créez des objets, je pense System.gcqu'il sera appelé automatiquement si nécessaire, mais pas pour créer des bitmaps. Cela échoue tout simplement.

Je recommande donc d'appeler manuellement System.gc()avant de créer des bitmaps.

Steve
la source
39
En effet, avant le nid d'abeille, les données bitmap ne sont pas stockées dans la VM et ne déclenchent donc pas le GC. Cela ne devrait pas être un problème dans Honeycomb et plus tard.
Timmmm
2
@Timmmm mais c'était en fait mon problème, je viens de définir largeheap sur true.
Lei Leyba
118

De manière générale, en présence d'un garbage collector, il n'est jamais bon d'appeler manuellement le GC. Un GC est organisé autour d'algorithmes heuristiques qui fonctionnent le mieux lorsqu'ils sont laissés à eux-mêmes. L'appel manuel du GC diminue souvent les performances.

Parfois , dans certaines situations relativement rares, on peut constater qu'un GC particulier se trompe, et un appel manuel au GC peut alors améliorer les choses, en termes de performances. En effet, il n'est pas vraiment possible de mettre en œuvre un GC "parfait" qui gérera la mémoire de manière optimale dans tous les cas. De telles situations sont difficiles à prévoir et dépendent de nombreux détails subtils de mise en œuvre. La «bonne pratique» est de laisser le GC fonctionner seul; un appel manuel au GC est l'exception, qui ne devrait être envisagée qu'après qu'un problème de performance réel a été dûment constaté.

Thomas Pornin
la source
8
+1 pour une bonne réponse indépendante de la plateforme. En attendant de voir si quelqu'un propose une réponse spécifique à Android avant de choisir.
hpique
8
Je suis d'accord avec ce que vous avez écrit si vous permettez à «performances» de signifier quelque chose de plus général que l'efficacité du processeur. Sur un appareil Android, la perception des performances par l'utilisateur est primordiale. Le développeur peut préférer exécuter le GC pendant que l'utilisateur appuie sur des boutons par exemple, afin que l'utilisateur ne soit pas au courant du GC.
President James K. Polk
5
Il est souvent important dans les jeux que le GC ne fonctionne pas pendant le jeu (cela nécessite que tous les objets soient pré-créés et recyclés ou similaires), mais lorsque le jeu est mis en pause, c'est le bon moment pour GC.
Pat
4
Pré-nid d'abeille, les données bitmap ne sont pas stockées dans la mémoire de la VM. Le système ne détectera pas lorsque vous avez utilisé trop de mémoire non-VM en raison des bitmaps et exécutera le GC (qui exécuterait les Bitmap.finalize()méthodes qui libèrent la mémoire non-VM). Par conséquent , dans ce cas, vous devriez aller au- dessus de la tête du GC et exécuter Bitmap.recycle()ou le System.gc()cas échéant. Mais seulement pré-nid d'abeille.
Timmmm
1
@ThomasPornin - D'un autre côté, en tant que programmeur d'application, vous savez quelque chose que le système d'exploitation ne sait pas: les moments auxquels votre application va maintenant faire un changement majeur dans la façon dont elle utilise la mémoire, et qu'il serait moins perturbant de l'expérience utilisateur de prendre une pause maintenant, qu'à un moment arbitraire dans le futur . Cela signifie qu'il peut être judicieux de faire des appels peu fréquents , lors de transitions majeures dans la façon dont l'application est utilisée. Celles-ci sont rares dans le sens où il ne faut pas appeler GC fréquemment, mais sont courantes dans la mesure où presque toutes les applications importantes ont de tels moments connus de par leur conception.
ToolmakerSteve
26

La mémoire insuffisante dans l'application Android est très courante si nous ne gérons pas correctement le bitmap, la solution au problème serait

if(imageBitmap != null) {
    imageBitmap.recycle();
    imageBitmap = null;
}
System.gc();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 3;
imageBitmap = BitmapFactory.decodeFile(URI, options);
Bitmap  scaledBitmap = Bitmap.createScaledBitmap(imageBitmap, 200, 200, true);
imageView.setImageBitmap(scaledBitmap);

Dans le code ci-dessus, je viens d'essayer de recycler le bitmap, ce qui vous permettra de libérer de l'espace mémoire utilisé, de sorte que la mémoire insuffisante peut ne pas se produire.J'ai essayé cela a fonctionné pour moi.

Si le problème persiste, vous pouvez également ajouter ces lignes

BitmapFactory.Options options = new BitmapFactory.Options();
options.inTempStorage = new byte[16*1024];
options.inPurgeable = true;

pour plus d'informations, consultez ce lien

https://web.archive.org/web/20140514092802/http://voices.yahoo.com/android-virtual-machine-vm-out-memory-error-7342266.html?cat=59


REMARQUE: en raison de la "pause" momentanée provoquée par l'exécution de gc, il n'est pas recommandé de le faire avant chaque allocation de bitmap.

La conception optimale est:

  1. Libérez tous les bitmaps qui ne sont plus nécessaires , par le if / recycle / nullcode affiché. (Faites une méthode pour vous aider.)

  2. System.gc();

  3. Attribuez les nouveaux bitmaps.

yogesh
la source
19

Si vous obtenez une OutOfMemoryError, il est généralement trop tard pour appeler le garbage collector ...

Voici une citation du développeur Android:

La plupart du temps, le garbage collection se produit en raison de tonnes de petits objets de courte durée et certains garbage collector, comme les garbage collors générationnels, peuvent optimiser la collecte de ces objets afin que l'application ne soit pas interrompue trop souvent. Le garbage collector Android n'est malheureusement pas en mesure d'effectuer de telles optimisations et la création d'objets de courte durée dans des chemins de code critiques pour les performances est donc très coûteuse pour votre application.

Donc, à ma connaissance, il n'y a aucun besoin urgent d'appeler le gc. Il est préférable de consacrer plus d'efforts à éviter la création inutile d'objets (comme la création d'objets à l'intérieur de boucles)

Andreas Dolk
la source
6
La citation ne peut-elle pas être interprétée dans l'autre sens? Peut-être que le GC doit être appelé manuellement afin de collecter ces objets avant qu'ils ne consomment trop de mémoire.
hpique
@hgpc: Je ne vois pas comment la citation peut être interprétée de la manière que vous suggérez. Je suppose que la documentation est une confession, admettant que leur GC est simple; lorsque la mémoire est faible, un GC complet est exécuté.
President James K. Polk
Utiliser pleinement des objets complexes et des frameworks utilisant des objets complexes tend à mieux utiliser le temps de développement qu'une optimisation prématurée. Se soucier de l'optimisation est un piège plus facile à tomber pour Android que pour Enterprise Java, car nous continuons inconsciemment à penser aux performances tout en codant une application mobile. D'autant que les développeurs de framework, qui doivent penser aux performances, divulguent ce point de vue dans leur documentation officielle lorsqu'ils ne font pas attention.
LateralFractal
9

Il semble System.gc()ne pas fonctionner sur Art Android 6.0.1 Nexus 5x, donc je l'utilise à la Runtime.getRuntime().gc();place.

cmicat
la source
1
System.gc()est une fonction wrapper pour Runtime.getRuntime().gc(). Voir android.googlesource.com/platform/libcore/+/…
Nathan F.
Oui, à partir de la source et de la documentation, il semble que ce soit la même chose, mais System.gc()cela ne fonctionne pas pour moi, mais Runtime.getRuntime().gc()ça fonctionne!
Ivan
7

Mon application gère beaucoup d'images et elle est morte avec une OutOfMemoryError. Cela m'a aidé. Dans le Manifest.xml, ajoutez

<application
....
   android:largeHeap="true"> 
Klykoo
la source
9
Google n'aime pas ça
Pedro Paulo Amorim
1
@PedroPauloAmorim explique pourquoi?
Machado
2
N'utilisez pas largeHeap tant que vous n'êtes pas sûr de ce que vous faites. L'utilisation de gros tas rend le garbage collector beaucoup plus difficile car il doit parcourir de nombreuses données indésirables avant d'effacer la mémoire.
Prakash
7

De manière générale, vous ne devez pas appeler GC explicitement avec System.gc (). Il y a même la conférence IO ( http://www.youtube.com/watch?v=_CruQY55HOk ) où ils expliquent ce que signifie le journal des pauses du GC et dans lequel ils déclarent également ne jamais appeler System.gc () car Dalvik sait mieux que vous quand le faire.

D'autre part, comme mentionné dans les réponses ci-dessus, le processus GC sous Android (comme tout le reste) est parfois bogué. Cela signifie que les algorithmes de Dalvik GC ne sont pas à égalité avec les JVM Hotspot ou JRockit et peuvent parfois se tromper. L'une de ces occasions est lors de l'allocation d'objets bitmap. C'est une question délicate car elle utilise la mémoire Heap et Non Heap et parce qu'une instance lâche d'objet bitmap sur un périphérique à mémoire limitée suffit à vous donner une exception OutOfMemory. Donc, l'appeler après que vous n'ayez plus besoin de ce bitmap est généralement suggéré par de nombreux développeurs et est même considéré comme une bonne pratique par certaines personnes.

Une meilleure pratique consiste à utiliser .recycle () sur un bitmap car c'est pour cela que cette méthode est faite, car elle marque la mémoire native du bitmap comme sûre à supprimer. Gardez à l'esprit que cela dépend beaucoup de la version, ce qui signifie qu'il sera généralement requis sur les anciennes versions d'Android (Pre 3.0 je pense) mais ne sera pas requis sur les versions ultérieures. De plus, cela ne fera pas beaucoup de mal de l'utiliser sur les versions plus récentes ether (ne faites pas cela en boucle ou quelque chose comme ça). Le nouveau runtime ART a beaucoup changé ici car ils ont introduit une "partition" spéciale pour les gros objets, mais je pense que cela ne fera pas beaucoup de mal de faire cela avec ART éther.

Aussi une note très importante sur System.gc (). Cette méthode n'est pas une commande à laquelle Dalvik (ou les JVM) sont obligés de répondre. Considérez cela plus comme dire à la machine virtuelle "Pourriez-vous s'il vous plaît faire un ramassage des ordures si ce n'est pas un problème".

Igor Čordaš
la source
3

Je dirais non, car les documents du développeur sur l' état d' utilisation de la RAM :

...
GC_EXPLICIT

Un GC explicite, comme lorsque vous appelez gc () (que vous devriez éviter d' appeler et à la place faire confiance au GC pour qu'il s'exécute en cas de besoin).

...

J'ai mis en évidence la partie pertinente en gras.

Jetez un œil à la série YouTube, Android Performance Patterns - elle vous montrera des conseils sur la gestion de l'utilisation de la mémoire de votre application (comme l'utilisation des ArrayMaps et SparseArrays d' Android au lieu de HashMaps).

Farbod Salamat-Zadeh
la source
3

Note rapide pour les développeurs Xamarin .

Si vous souhaitez appeler System.gc()dans les applications Xamarin.Android, vous devez appelerJava.Lang.JavaSystem.Gc()

Denis Gordin
la source
2

Il n'est pas nécessaire d'appeler le garbage collector après un fichier OutOfMemoryError.

C'est Javadoc déclare clairement:

Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.

Ainsi, le garbage collector a déjà essayé de libérer de la mémoire avant de générer l'erreur, mais n'a pas réussi.

perdian
la source
8
L'Android Javadoc ne l'indique pas et sa mise en œuvre est probablement différente. d.android.com/reference/java/lang/OutOfMemoryError.html
hpique
Vous avez raison de dire que cela ne s'applique pas sur Android. Mais là encore, vous ne pouvez pas gérer OOE au runtime ether, vous ne pouvez donc pas faire grand-chose à ce sujet même si cela était / n'était pas vrai.
Igor Čordaš