Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory leak when creating bitmaps in a loop

I have an map app. Somewhere in my code I am rendering data from database into canvas. I ran into "out of memory" exception and I cant figure out how to avoid it.

Here is the relevant method. I get exception when creating bitmap with 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);
}

I have tried recycling the image, but then the canvas coplains it cant work with recycled bitmaps.

Any solution would be much apreciated.

like image 356
no9 Avatar asked Jun 17 '26 08:06

no9


1 Answers

I would suggest having a bitmap cache. Even recycling images on pre-honeycomb takes time to free memory (Bitmap data is stored in native memory that is not directly managed by dalvik). Here is a sample of a bitmap cache. Please adjust it to your needs.

/**
 * @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();
        }
    }
}
like image 91
Audrius Avatar answered Jun 18 '26 20:06

Audrius



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!