4

У меня происходит утечка памяти в моем приложении, которое запускает GC несколько раз и вызывает проблемы с производительностью. Я создал leak suspect report, используя MAT. Вот отчет:Bitmap Memory leak - Android

Проблема Подозреваемый 1: Один экземпляр "android.graphics.Bitmap" загружен "" занимает 4,194,368 (20,13%) байт. Память накапливается в одном экземпляре «byte []», загружаемом «».

Проблема Подозреваемый 2: Класс "android.content.res.Resources", нагружен "", занимает 3,962,504 (19,02%) байт. Память накапливается в одном экземпляре «java.lang.Object []», загруженного «».

Задача Подозреваемый 3: Один экземпляр "android.graphics.Bitmap" загружен "" занимает 3,145,792 (15,10%) байт. Память накапливается в одном экземпляре «byte []», загружаемом «».

Судя по сообщениям, очевидно, что утечка памяти происходит из-за растрового изображения. Я много исследовал, но не смог исправить эту утечку. Пожалуйста, помогите мне. Я использую класс ImageLoader для загрузки и отображения растровых изображений. Чтобы использовать этот класс, я просто вызываю метод displayImage(). Вот код:

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); 
        } 
       } 
      }); 
     } 
    } 

} 

Пожалуйста, помогите мне исправить свой код. Благодаря!

Примечание: Я не использовал bitmap.recycle() с тех пор, в документации сказано, что после Honeycomb ГХ собирает растровые изображения и его больше нет необходимости, чтобы принудительно утилизировать его!

+0

Вы получаете утечку памяти в случайное время, всегда в то же время, когда вы вращаете устройство ...? – Fustigador

+0

Вы должны прочитать о SoftReference в Android doc, в вашем случае, если вы где-нибудь сохранили возвращаемый Bitmap, он останется в памяти –

+0

@Fustigador всякий раз, когда я делаю какие-либо действия, связанные с загрузкой изображений. Не специально вращать устройство. – gauravsapiens

ответ

0

Проблемы с утечкой памяти всегда проблемы Java. Я понимаю ваш код, код простой инструмент imagecache. Проверьте значение SampleSize и службу-исполнитель запустите только один поток. Четыре потока имеют большую память и это действие фонового потока. Обмен вашего «обработчика» на «runOnUIThread»

Вы должны использовать;

Деятельность Деятельность = (Деятельность) 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

Я уже пробовал это, но это не помогло, скорее это могло бы лишнее ссылаться на «Активность». – gauravsapiens

+0

Я использую imagecache так же, как ваш код, но я не получаю ошибку утечки памяти. Я отправил свой код через 2-3 часа, если вы этого захотите. Вы даете мне ссылку на связь, такую ​​как «электронная почта». Я отправлю группу java-файлов. (Пакет) – nurisezgin

+0

Да, мой почтовый идентификатор - [email protected] Благодаря ! :) – gauravsapiens

0

Я думаю, что проблема является экземпляр Singleton ... Я сделал форк проекта LazyList, проверить это:

https://github.com/nicolasjafelle/LazyList

У меня такая же утечка памяти, но и, возможно, я я ошибаюсь, этот синглтон никогда не будет собран мусором, если вы не убьете процесс с помощью System.exit().

Именно поэтому оригинальный проект LazyList не использует Singleton. Я также думаю, что если вам нужен кеш, вам нужно быть быстрым и одинаковым для всего приложения.

Важная вещь в этом ImageLoader - это FileCache и MemoryCache, когда вы вызываете clearCache растровые изображения, где собраны.

0

Я думаю, что ответ прост, просто продолжайте очищать кеш, когда вам не нужна память/когда возникает исключение OOM. Я сделал это для вас

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; 
    }