当前位置:   article > 正文

android内存溢出OutOfMemeory (OOM)_caused by: java.lang.outofmemoryerror: oom allocat

caused by: java.lang.outofmemoryerror: oom allocating bitmap with dimensions

android内存溢出OutOfMemeory (OOM)

分类: android native app   123人阅读  评论(1)  收藏  举报

下面这些都是我在做各个app时总结出来的,希望对各位有用:


1.Android内存溢出原因

  • 当图片过大,或图片数量较多时使用BitmapFactory解码图片会出java.lang.OutOfMemoryError: bitmap size exceeds VM budget,要想正常使用则需分配更少的内存
  • 具体的解决办法是修改采样值BitmapFactory.Options.inSampleSize;设置此数值后会将图片的长宽缩放此int值后读入内存

2.恰当的inSampleSize

  • BitmapFactory.Options提供了另一个成员inJustDecodeBounds;设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。
  • Android提供了一种动态计算的方法
    public static int computeSampleSize(BitmapFactory.Options options,
            int minSideLength, int maxNumOfPixels) {
        int initialSize = computeInitialSampleSize(options, minSideLength,maxNumOfPixels);
    
        int roundedSize;
        if (initialSize <= 8 ) {
            roundedSize = 1;
            while (roundedSize < initialSize) {
                roundedSize <<= 1;
            }
        } else {
            roundedSize = (initialSize + 7) / 8 * 8;
        }
    
        return roundedSize;
    }
    
    private static int computeInitialSampleSize(BitmapFactory.Options options,int minSideLength, int maxNumOfPixels) {
        double w = options.outWidth;
        double h = options.outHeight;
    
        int lowerBound = (maxNumOfPixels == -1) ? 1 :
                (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
        int upperBound = (minSideLength == -1) ? 128 :
                (int) Math.min(Math.floor(w / minSideLength),
                Math.floor(h / minSideLength));
    
        if (upperBound < lowerBound) {
            // return the larger one when there is no overlapping zone.
            return lowerBound;
        }
    
        if ((maxNumOfPixels == -1) &&
                (minSideLength == -1)) {
            return 1;
        } else if (minSideLength == -1) {
            return lowerBound;
        } else {
            return upperBound;
        }
    }
    
  • 使用该算法,就可动态计算出图片的inSampleSize
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imageFile, opts);

opts.inSampleSize = computeSampleSize(opts, -1, 128*128);
opts.inJustDecodeBounds = false;
try {
	Bitmap bmp = BitmapFactory.decodeFile(imageFile, opts);
	imageView.setImageBitmap(bmp);
    } catch (OutOfMemoryError err) {
}


3.使用ListView展示图片

大部分的app都是使用ListView来展示图片的,其实ListView的adapter是可以重用每个list的view的:

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		Log.e("ok", "position:"+position);
		if (convertView == null) { // 这句就是重用的关键
			convertView = LayoutInflater.from(context).inflate(R.layout.xxx, null);
		}
        }

重用convertView的方式也是google推荐的,这样系统是可以自动回收已经滑出屏幕的资源的。

但是重用convertView会有一个问题,就是如果图片是异步加载的,快速滑动listview时每个list的上的图片会不停的闪(以前做省电宝的时候遇到过这个bug),这个bug是由于我没有判断ImageView控件是否是重用的而引起的。 要解决这个bug,只需在异步加载图片的时候根据每个ImageView的tag判断一下ImageView是否重用:

    boolean imageViewReused(ImageView iv, URL url) {
        String tag=imageViewsHashMap.get(iv); // imageViewsHashMap是用来存储ImageView和tag的对应关系的(我是用图片的url来标识的tag,这个tag可以随意取值,只要能唯一的标识这个ImageView就好了)
        if(tag==null || !tag.equals(url)) {
            return true;
        }
        return false;
    }

如果ImageView是重用的,就先设置一张默认的图片,等异步加载完成后再设置成最终要展示的图片。 如果ImageView不是重用的,忽略。

4.View隐藏或Activity退出时释放所有的Bitmap资源

之前在做壁纸的时候一直出现OOM的问题,找了好久都没有发现是怎么回事,之前做市场的时候也有遇到过,而且我确定我在使用了所有的Bitmap以后都手动释放了那些资源。这是一个很奇怪的事情,虽然我现在解了这个bug了,但是有些android的机制我还不是很理解,也希望有大拿指导一下。


下面是解决方案:

ImageView是存储在JVM里面的,但是Bitmap是存储在native heap里面的(3.0之前的系统是这样的),壁纸有一个大图浏览界面(一个Activity),每次进入这个界面的时候都会加载一张大图(大概在70K-200K),我加载大图的代码:

imageView.setImageBitmap(bitmap); // 

我在每次Activity退出时都会主动的回收掉这个bitmap,代码:

if(bitmap != null && !bitmap.isrecycle) {
    bitmap.recycle(); // 主动释放以后系统再GC也不管用,不知道为什么,我也尝试过对bitmap使用软引用/弱应用等,也都是不起作用
}

我在DDMS里面看到系统也会执行GC,但是就是不会回收我释放的这些资源,多次(一般3-5次)进入大图浏览界面以后一般就会报OOM的错误了。

后来我把退出时的代码改成了下面的形式:

imageView.setImageBitmap(null); // 不是主动的回收bitmap,而是主动的释放对bitmap的引用
imageView = null;

我从DDMS里面看到资源基本都被回收了,壁纸也基本不会再报OOM的错误了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/443806
推荐阅读
相关标签
  

闽ICP备14008679号