的OutOfMemoryError:位图大小超过VM预算 [英] OutOfMemoryError: bitmap size exceeds VM budget

查看:165
本文介绍了的OutOfMemoryError:位图大小超过VM预算的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对不起,这似乎是一个重复的问题,但我觉得我没有资格对任何已经发布的建议。

我已经在我的应用程序最多20幅图像的画廊。打丢的同时来回后,我得到的OutOfMemoryError。

但奇怪的是,我不持有任何静态引用,我已经搜索了可能的内存泄漏我可以保证,我没有找到为止。

总之,20幅图像(100KB平均的PNG)并不像那么多。我已经实现了一个视图缓存,SoftReference的持有者为位图,等等。

这是100KB的平均20 PNG图像足以杀死我的应用程序?当真?我怎样才能摆脱呢?我跟着这个伟大的职位也

的http://博客.jteam.nl / 2009/09/17 /探索最世界的,Android的部分-2 /

任何更多的想法?

这是ImageCache:

 公共类AsyncImageLoader {    私人最终字符串标记=的getClass()getSimpleName()。
    私人语境mContext;
    私人的HashMap<弦乐,SoftReference的<&位图GT;> mImageCache;    公共AsyncImageLoader(上下文的背景下){
        mContext =背景;
            mImageCache =新的HashMap<弦乐,SoftReference的<&位图GT;>();
    }    公共位图的LoadImage(最后字符串的标识,最后弦乐的ImagePath,最终ImageCallback imageCallback){        如果(mImageCache.containsKey(的ImagePath)){
            SoftReference的<&位图GT; SoftReference的= mImageCache.get(的ImagePath);
            位图的位图= softReference.get();
            如果(位图!= NULL){
                Log.i(TAG,从缓存中检索形象:+的ImagePath);
                返回位图;
            }
        }        最后的处理程序处理程序=新的处理程序(){
            @覆盖
            公共无效的handleMessage(消息消息){
                imageCallback.imageLoaded((位图)message.obj,的ImagePath,标识符);
            }
        };        新的Thread(){            @覆盖
            公共无效的run(){
                位图位图= loadImageFromPath(的ImagePath);
                mImageCache.put(的ImagePath,新SoftReference的<&位图GT;(位图));
                消息消息= handler.obtainMessage(0,位图);
                handler.sendMessage(消息);
            }        }。开始();        返回null;
    }    公共位图loadImageFromPath(字符串路径){        如果(!GeneralUtilities.isEmpty(路径)){
            Log.i(TAG加载图像:+路径);
            InputStream中的ImageInputStream = NULL;            尝试{
                最后AssetManager assetManager = mContext.getResources()getAssets()。
                的ImageInputStream = assetManager.open(路径);                位图位图= GeneralUtilities.de codeFILE(ImageInputStream中);                imageInputStream.close();                返回位图;
            }赶上(最终IOException异常五){
                Log.e(TAG,e.getMessage());
            }
        }        返回null;
    }    公共接口ImageCallback {
        公共无效imageLoaded(位图imageBitmap,字符串的ImagePath,字符串标识符);
    }
}

和方法GeneralUtilities.de codeFILE是:

 公共静态位图德codeFILE(InputStream为){
        //德code图像尺寸
        BitmapFactory.Options O =新BitmapFactory.Options();
        o.inJustDe codeBounds = TRUE;
        BitmapFactory.de codeStream(是,空,O);        //我们希望新的大小缩放到
        最终诠释REQUIRED_SIZE = 140;        //找到正确的比例值。它应该是2的幂。
        INT width_tmp = o.outWidth,height_tmp = o.outHeight;
        int标= 1;        而(真){
            如果(width_tmp / 2'; REQUIRED_SIZE || height_tmp / 2版; REQUIRED_SIZE)
                打破;
            width_tmp / = 2;
            height_tmp / = 2;            规模* = 2;
        }        //德code。与inSampleSize
        BitmapFactory.Options O2 =新BitmapFactory.Options();
        o2.inSampleSize =规模;
        返回BitmapFactory.de codeStream(是,空,O2);
      }

而在一个ArrayAdapter的getView我已经是这样的:

 最后的ImageView itemImage = cache.getHistoryImage();
        //最后的ImageView itemFrame = cache.getFrame();        。字符串文件名= item.getFilename()修剪();        itemImage.setTag(front_+文件名);        位图cachedImage = mAsyncImageLoader.loadImage(front_+文件名,文件名,新ImageCallback(){            公共无效imageLoaded(位图imageBitmap,字符串的ImagePath,字符串标识符){                ImageView的imageViewByTag =(ImageView的)mGallery.findViewWithTag(标识);
                如果(imageViewByTag!= NULL){
                    imageViewByTag.setImageBitmap(imageBitmap);
                }
            }
        });        itemImage.setImageBitmap(cachedImage);


解决方案

有似乎是在Android框架中的错误,虽然谷歌似乎否认。

您是否通过发行8488看?

HTTP://$c$c.google。 COM / p /安卓/问题/细节?ID = 8488

我不知道这是否适用于你的code - 但你可能设置/在ImageView的更新映像之前尝试的建议

基本上,它归结为调用Bitmap.recycle(),调零引用(可能你的情况irrellevant)和显式调用调用System.gc()。

垃圾收集器似乎异步运行和新的可能会失败,即使内存可以被释放。

Sorry it seems like a repeated question, BUT I think I don't qualify to any of the recommendations already posted.

I've a Gallery of maximum 20 images on my application. After playing a while flinging back and forth I'm getting OutOfMemoryError.

The strange thing is that I don't hold any static references, and I've searched for possible memory leaks I can assure that I've not found one so far.

Anyway, 20 images (PNG of 100KB on average) doesn't be like that much. And I've implemented a view cache, SoftReference holders for the bitmaps, etc.

Is it 20 PNG images of 100KB on average enough to kill my app?? seriously? how can I get rid of this? I've followed this great post also

http://blog.jteam.nl/2009/09/17/exploring-the-world-of-android-part-2/

Any more ideas?

This is the ImageCache:

public class AsyncImageLoader {

    private final String TAG = getClass().getSimpleName();
    private Context mContext;
    private HashMap<String, SoftReference<Bitmap>> mImageCache;

    public AsyncImageLoader(Context context) {
        mContext = context;
            mImageCache = new HashMap<String, SoftReference<Bitmap>>();
    }

    public Bitmap loadImage(final String identifier, final String imagePath, final ImageCallback imageCallback) {

        if (mImageCache.containsKey(imagePath)) {
            SoftReference<Bitmap> softReference = mImageCache.get(imagePath);
            Bitmap bitmap = softReference.get();
            if (bitmap != null) {
                Log.i(TAG, "Retrieving image from cache: " + imagePath);
                return bitmap;
            }
        }

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                imageCallback.imageLoaded((Bitmap) message.obj, imagePath, identifier);
            }
        };

        new Thread() {

            @Override
            public void run() {
                Bitmap bitmap = loadImageFromPath(imagePath);
                mImageCache.put(imagePath, new SoftReference<Bitmap>(bitmap));
                Message message = handler.obtainMessage(0, bitmap);
                handler.sendMessage(message);
            }

        }.start();

        return null;
    }

    public Bitmap loadImageFromPath(String path) {

        if(!GeneralUtilities.isEmpty(path)) {
            Log.i(TAG, "Loading image: " + path);
            InputStream imageInputStream = null;

            try {               
                final AssetManager assetManager = mContext.getResources().getAssets(); 
                imageInputStream = assetManager.open(path);

                Bitmap bitmap = GeneralUtilities.decodeFile(imageInputStream);

                imageInputStream.close();

                return bitmap;
            } catch (final IOException e) {
                Log.e(TAG, e.getMessage());
            }        
        }

        return null;
    }

    public interface ImageCallback {
        public void imageLoaded(Bitmap imageBitmap, String imagePath, String identifier);
    }
}

and the method GeneralUtilities.decodeFile is:

public static Bitmap decodeFile(InputStream is){
        //Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(is, null, o);

        //The new size we want to scale to
        final int REQUIRED_SIZE=140;

        //Find the correct scale value. It should be the power of 2.
        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;
        }

        //Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeStream(is, null, o2);  
      }

And in the getView of the ArrayAdapter I've something like this:

final ImageView itemImage = cache.getHistoryImage();        
        //final ImageView itemFrame = cache.getFrame();

        String filename = item.getFilename().trim();

        itemImage.setTag("front_" + filename);

        Bitmap cachedImage = mAsyncImageLoader.loadImage("front_" + filename, filename, new ImageCallback() {

            public void imageLoaded(Bitmap imageBitmap, String imagePath, String identifier) {

                ImageView imageViewByTag = (ImageView) mGallery.findViewWithTag(identifier);
                if (imageViewByTag != null) {
                    imageViewByTag.setImageBitmap(imageBitmap);
                }
            }
        });

        itemImage.setImageBitmap(cachedImage);

解决方案

There seems to be a bug in the Android framework, although Google seems to deny it.

Did you read through issue 8488?

http://code.google.com/p/android/issues/detail?id=8488

I am not sure if this applies to your code - but you might try the recommendations before setting/updating the image on the ImageView.

Basically, it boils down to calling Bitmap.recycle(), nulling references (probably irrellevant in your case) and explicitly calling calling System.gc().

The garbage collector seems to run asynchronously and a new might fail even though memory could be freed.

这篇关于的OutOfMemoryError:位图大小超过VM预算的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆