3 votes

Fuite de mémoire lors de la création de bitmaps dans une boucle

J'ai une application cartographique. Quelque part dans mon code, je rends les données de la base de données dans le canevas. J'ai rencontré une exception "out of memory" et je n'arrive pas à comprendre comment l'éviter.

Voici la méthode correspondante. J'obtiens une exception lors de la création d'une image avec bitmapfactory.

private static void _renderImage(Canvas g, Point[] points, RImageData imageData, 
                                 RMapView mapView) {

    Bitmap image = (Bitmap)imageData.image;
    Paint paint = new Paint();
    if(image == null) {
        image = BitmapFactory.decodeByteArray(imageData.getImageBytes(), 0,
                                              imageData.getImageBytes().length);
        imageData.image = image;
    }
    g.drawBitmap(image, points[0].x, points[0].y, paint);
}

J'ai essayé de recycler l'image, mais le canevas confirme qu'il ne peut pas fonctionner avec des bitmaps recyclés.

Toute solution serait très appréciée.

2voto

Audrius Points 1706

Je suggère d'avoir un cache bitmap. Même le recyclage des images sur pre-honeycomb prend du temps pour libérer la mémoire (les données bitmap sont stockées dans la mémoire native qui n'est pas directement gérée par dalvik). Voici un exemple de cache bitmap. Veuillez l'adapter à vos besoins.

/**
 * @author audrius Bitmap cache
 */
private static class BitmapCache {
    //private static final String TAG = "BitmapCache";
    private final int mCacheSize;
    private final String mBitmapLocation;
    private LinkedHashMap<String, Bitmap> mBitmapCache;

    /**
     * Constructor
     * 
     * @param cacheSize
     *            Cache size in element count (e.g. 8 = at most 8 Bitmaps in
     *            cache)
     * @param bitmapLocation
     *            Physical root path to bitmap location
     */
    public BitmapCache(int cacheSize, String bitmapLocation) {
        mCacheSize = cacheSize;
        mBitmapLocation = bitmapLocation;

        mBitmapCache = new LinkedHashMap<String, Bitmap>(mCacheSize + 1) {
            private static final long serialVersionUID = -4156123801558395154L;

            @Override
            protected boolean removeEldestEntry(
                    java.util.Map.Entry<String, Bitmap> eldest) {
                return size() > mCacheSize;
            };

            @Override
            public Bitmap remove(Object key) {
                Bitmap bmp = super.get(key);
                // make sure to release resources as soon as possible
                bmp.recycle();
                return super.remove(key);
            }
        };
    }

    /**
     * Returns Bitmap (either from cache or physical location)
     * 
     * @param bitmapFilename
     * @return
     */
    public Bitmap getBitmap(String bitmapFilename) {
        Bitmap ret = mBitmapCache.get(bitmapFilename);
        //Log.v(TAG, "getBitmap : " + bitmapFilename);
        if (ret == null) {
            //Log.v(TAG, "Bitmap not cached, reading location : " + mBitmapLocation);
            ret = BitmapFactory.decodeFile(new File(mBitmapLocation, bitmapFilename).getAbsolutePath());
            mBitmapCache.put(bitmapFilename, ret);
        }

        return ret;
    }

    /**
     * Clears bitmap cache
     */
    public void clear() {
        if (mBitmapCache != null) {
            for (Bitmap bitmap : mBitmapCache.values()) {
                if (bitmap != null) bitmap.recycle();
            }

            mBitmapCache.clear();
        }
    }
}

1voto

Stephen C Points 255558

J'ai essayé de recycler l'image, mais le canevas confirme qu'il ne peut pas fonctionner avec des bitmaps recyclés.

Je pense que l'idée est que vous êtes censé "recycler" le bitmap et le laisser tomber par terre pour que le ramasse-miettes s'en occupe.

Voici ce que dit la javadoc à propos de recycle() :

"Libère l'objet natif associé à cette image bitmap et efface la référence aux données de pixels. Cette opération ne libère pas les données des pixels de manière synchrone ; elle permet simplement de les mettre à la poubelle s'il n'y a pas d'autres références. Le bitmap est marqué comme "mort", ce qui signifie qu'il lèvera une exception si getPixels() ou setPixels() est appelé, et qu'il ne dessinera rien. Cette opération ne peut pas être annulée, donc elle ne doit être appelée que si vous êtes sûr qu'il n'y a plus d'autres utilisations pour le bitmap. Il s'agit d'un appel avancé, qui n'a normalement pas besoin d'être appelé, puisque le processus GC normal libérera cette mémoire lorsqu'il n'y aura plus de références à ce bitmap".

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