4

アプリでメモリリークが発生し、GCが何度もトリガーされ、パフォーマンスの問題が発生しています。leak suspect reportを使用して生成しましたMAT。レポートは次のとおりです。

問題の疑い1: 「」によってロードされた「android.graphics.Bitmap」の1つのインスタンスは、4,194,368(20.13%)バイトを占有します。メモリは、「」によってロードされた「byte[]」の1つのインスタンスに蓄積されます。

問題の疑い2: 「」によってロードされたクラス「android.content.res.Resources」は、3,962,504(19.02%)バイトを占有します。メモリは、「」によってロードされた「java.lang.Object[]」の1つのインスタンスに蓄積されます。

問題の疑い3: 「」によってロードされた「android.graphics.Bitmap」の1つのインスタンスは、3,145,792(15.10%)バイトを占有します。メモリは、「」によってロードされた「byte[]」の1つのインスタンスに蓄積されます。

レポートから判断すると、メモリリークはビットマップが原因であることが明らかです。私は多くのことを研究しましたが、このリークを修正することができませんでした。私を助けてください。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()。ドキュメントには、ハニカム後のGCがビットマップを収集し、強制的にリサイクルする必要がなくなったと記載されています。

4

4 に答える 4

0

問題は Singleton インスタンスだと思います... LazyList プロジェクトのフォークを作成しました。これを確認してください:

https://github.com/nicolasjafelle/LazyList

私は同じメモリリークを抱えていますが、おそらく私が間違っているかもしれません.System.exit()でプロセスを強制終了しない限り、このシングルトンはガベージコレクションされません。

これが、元の LazyList プロジェクトが Singleton を使用しない理由です。また、キャッシュが必要な場合は、高速で、すべてのアプリケーションで同じである必要があると思います。

この ImageLoader で重要なのは FileCache と MemoryCache です。clearCache を呼び出すと、ビットマップが収集されます。

于 2013-02-18T15:27:21.313 に答える
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;
    }
于 2013-12-10T15:56:55.293 に答える
0

メモリ リークの問題は常に Java の問題です。私はあなたのコード、単純なイメージキャッシュ ツールのコードを理解しています。SampleSize の値と executor サービスが 1 つのスレッドのみで実行されていることを確認してください。4 つのスレッドには大きなメモリがあり、このバックグラウンド スレッド アクションがあります。「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);
                    }
});
于 2013-02-18T13:57:05.380 に答える