9 votes

Y a-t-il un moyen de compacter la mémoire dans Android pour abaisser le niveau de la hauteur d'eau élevée ?

Veuillez noter que je N'AI PAS de fuite de mémoire. Ma question concerne un problème plus subtil.

Récemment, j'ai écrit une application Android qui effectue du traitement d'image. L'image est chargée en tant que Bitmap, puis copiée en pixels, traitée de manière à utiliser beaucoup de mémoire (pensez aux transformations de Fourier en représentations en virgule flottante et autres), puis convertie de nouveau en bitmap et enregistrée.

Le problème est que, au moins jusqu'à Android OS 2.3, la limitation totale de mémoire (généralement 16 Mo) combine le java et les Bitmaps (stockés à l'extérieur), et la ligne de flottaison du java ne diminue pas (à ce que je puisse discerner) même lorsque la mémoire est libérée (avec succès GC'd), ce qui signifie que lorsque je vais allouer le Bitmap final, je suis souvent "sans mémoire" même si à ce stade j'ai libéré (et GC'd) la plupart de l'espace. En d'autres termes, je n'ai jamais besoin des 16 Mo complets en une fois, mais l'espace restant pour les Bitmaps semble être de 16 Mo moins l'utilisation historique MAX de la pile java (par opposition à l'utilisation actuelle).

J'ai regardé une présentation technique par l'un des développeurs Android sur les problèmes de mémoire et il a laissé entendre que ce problème a été corrigé dans les versions ultérieures du système d'exploitation (ils ont déplacé la mémoire Bitmap dans l'espace de la pile java), mais en attendant la plupart des personnes qui veulent utiliser mon application exécutent 2.2 ou 2.3.

En résumé, je me demande si la pile java est jamais compactée (défragmentée, en effet) de sorte que la ligne de flottaison diminue (et si c'est le cas, comment le faire arriver)?

Si ce n'est pas le cas, quelqu'un a-t-il une autre suggestion pour résoudre ce problème ?

1voto

CommonsWare Points 402670

En résumé, je me demande si le tas Java est jamais compacté (défragmenté, en effet) de sorte que la marque haute diminue (et si oui, comment le faire ?)

Quel que soit son comportement, il n'est certainement pas sous votre contrôle.

Sinon, est-ce que quelqu'un a une autre suggestion pour gérer ce problème ?

Idéalement, réutilisez vos propres Bitmaps. Vous ne précisez pas ce que signifie vraiment "traité de manière à utiliser beaucoup de mémoire". Cependant, si cela ne modifie pas les dimensions ou la profondeur de bits de l'image, copiez les données de retour dans le Bitmap d'origine plutôt que d'en allouer un nouveau, si possible.

Le traitement d'image sur Android 2.x est l'un des rares endroits où je peux justifier l'utilisation de plusieurs processus. Vous ajouterez des frais généraux pour déplacer les données de l'image entre les processus, mais l'autre processus a sa propre pile (Java et native), donc cela peut vous donner plus de "marge de manœuvre".

1voto

Tamil Points 11

Jusqu'à présent, aucune indication qu'il y ait un moyen de compacter la mémoire.

Voici ma solution de contournement, qui est suboptimale mais beaucoup mieux que le comportement précédent :

Je garde maintenant intentionnellement le Bitmap d'origine pendant le traitement, puis je le recycle() et le nullifie, et je fais un GC(), mais pas juste avant d'allouer mon Bitmap de sortie.

Ce que cela fait, c'est réserver de l'espace externe (Bitmap) et provoquer un dépassement de la mémoire java (pendant le traitement, avant d'appeler recycle()), que je peux du moins attraper et gérer en réessayant avec une image plus petite. (Auparavant, tout semblait aller bien jusqu'à ce que j'essaie de sauvegarder, mais à ce moment-là c'était trop tard et sans moyen de récupération.)

Techniquement, cela limite la taille maximale de mon image à moins que ce que je devrais pouvoir faire avec la mémoire allouée (car j'ai besoin de réserver de l'espace dans le heap et à l'extérieur en même temps alors qu'en réalité je n'ai jamais besoin des deux ensemble), mais au moins je peux toujours gérer une taille d'image raisonnable.

Ce qui se passait avant, c'est que je libérais et recyclais le Bitmap trop tôt, ce qui permettait au point d'eau élevé sur le tas java d'utiliser essentiellement toute mon allocation mémoire, ce qui signifie qu'à partir de ce moment-là, je ne pouvais plus ouvrir ou créer d'autres Bitmaps du tout (à part parfois de très petites tailles de vignettes).

À mon avis, il s'agit d'un bogue majeur dans la manière dont Android gère la mémoire des Bitmaps, mais je crois que c'est corrigé dans les nouvelles versions du système d'exploitation, donc j'espère pouvoir désactiver cette solution de contournement en fonction de la version du système d'exploitation.

0voto

Pedro Loureiro Points 6889

Je pars du principe que vous appelez déjà Bitmap.recycle() mais c'est la seule chose dont je me souviens et que vous n'avez pas mentionnée.

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