Bitmap Memory Leak - Android

I have a memory leak in my application that launches the GC several times and causes performance issues. I created a leak suspect report using MAT . Here is the report:

Problem Suspect 1: One instance of "android.graphics.Bitmap" loaded "occupies 4,194,368 (20,13%) bytes. The memory is accumulated in one instance of" byte [] "loaded by" ".

Problem Suspect 2: The class "android.content.res.Resources" loaded "occupies 3962,504 (19.02%) bytes. The memory is accumulated in one instance of" java.lang.Object [] "loaded by" ".

Problem Suspect 3: One instance of "android.graphics.Bitmap" loaded "occupies 3,145,792 (15,10%) bytes. The memory is accumulated in one instance of" byte [] "loaded by" ".

Judging by the reports, it is obvious that the memory leak is due to the bitmap. I researched a lot, but could not fix this leak. Please help me. I use a class ImageLoader to load and display bitmaps. To use this class, I simply call the displayImage() method. Here is the code:

 public class ImageLoader { private static ImageLoader imageLoader; private int maxNoOfConnections = 4; FileCache fileCache; ExecutorService executorService; HttpURLConnection conn; InputStream is; OutputStream os; PhotosLoader photosLoader; Handler handler; Bitmap bitmap; private ImageLoader(Context context) { fileCache = new FileCache(context); executorService = Executors.newFixedThreadPool(maxNoOfConnections); handler = new Handler(); } public static ImageLoader getInstance(Context context) { if (imageLoader == null) imageLoader = new ImageLoader(context); return imageLoader; } public void displayImage(String url, ProgressBar pBar, ImageView imageView) { photosLoader = new PhotosLoader(url, imageView, pBar); executorService.submit(photosLoader); } private Bitmap getBitmap(String url) { File f = fileCache.getFile(url); bitmap = decodeFile(f); if (bitmap != null) return bitmap; try { URL imageUrl = new URL(url); conn = (HttpURLConnection) imageUrl.openConnection(); conn.setConnectTimeout(30000); conn.setReadTimeout(30000); conn.setInstanceFollowRedirects(true); is = conn.getInputStream(); os = new FileOutputStream(f); Utils.CopyStream(is, os); os.close(); bitmap = decodeFile(f); return bitmap; } catch (Exception ex) { Log.e("inNews", "Image Url Malformed"); return null; } } private Bitmap decodeFile(File f) { try { BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream(new FileInputStream(f), null, o); final int REQUIRED_SIZE = 70; int width_tmp = o.outWidth, height_tmp = o.outHeight; int scale = 1; while (true) { if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE) break; width_tmp /= 2; height_tmp /= 2; scale *= 2; } BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize = scale; return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); } catch (FileNotFoundException e) { } return null; } class PhotosLoader implements Runnable { String url; ImageView imageView; ProgressBar pBar; Bitmap bmp; public PhotosLoader(String url, ImageView imageView, ProgressBar pBar) { this.url = url; this.imageView = imageView; this.pBar = pBar; } @Override public void run() { bmp = getBitmap(url); handler.post(new Runnable() { @Override public void run() { if (bmp != null) { pBar.setVisibility(View.GONE); imageView.setImageBitmap(bmp); } else { pBar.setVisibility(View.GONE); imageView.setImageResource(R.drawable.img_no_image_grid); } } }); } } } 

Please help me fix my code. Thanks!

Note: I did not use bitmap.recycle() , as the documentation says that post-Honeycomb GC collects bitmaps, and it no longer needs to be forced to recycle!

+4
source share
3 answers

A memory leak problem is always related to Java problems. I understand your code, code is a simple imagecache tool. Check the value of SampleSize and the executor service only start one thread. Four threads have a large memory and this is a background thread action. Exchange "handler" to "runOnUIThread"

You must use;

Activity activity = (activity) imageView.getContext ();

 __activity__.runOnUIThread(new Runnable() { if (bmp != null) { pBar.setVisibility(View.GONE); imageView.setImageBitmap(bmp); } else { pBar.setVisibility(View.GONE); imageView.setImageResource(R.drawable.img_no_image_grid); } }); 
0
source

I think the problem is in the Singleton instance ... I made a fork of the LazyList project, check this:

https://github.com/nicolasjafelle/LazyList

I have the same memory leak, but maybe I'm wrong, this singleton will never be garbage collected unless you kill the process with System.exit ().

This is why the original LazyList project does not use Singleton. I also think that if you need a cache, you need to be fast and the same for the whole application.

The important thing in this ImageLoader is FileCache and MemoryCache when you call clearCache bitmaps that are compiled.

0
source

I think the answer is simple, just keep flushing the cache when you don't need memory / when an OOM exception is thrown. I did it for you.

 MemoryCache memoryCache = new MemoryCache(); try { Bitmap bitmap = null; URL imageUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection) imageUrl .openConnection(); conn.setConnectTimeout(30000); conn.setReadTimeout(30000); conn.setInstanceFollowRedirects(true); InputStream is = conn.getInputStream(); OutputStream os = new FileOutputStream(f); Utils.CopyStream(is, os); os.close(); conn.disconnect(); bitmap = decodeFile(f); return bitmap; } catch (Throwable ex) { ex.printStackTrace(); if (ex instanceof OutOfMemoryError) memoryCache.clear(); return null; } 
0
source

All Articles