android Bitmap和OOM

本文深入探讨了Android中Bitmap的内存管理机制,包括不同版本的处理方式,如recycle()方法的使用,以及BitmapFactory.Options.inBitmap字段的内存复用特性。提供了详细的示例代码和建议,帮助开发者避免内存泄漏和优化性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Bitmap OOM Sample:

Bitmap mB=null,mB2,mB3;

@Override
public void onBackPressed() {
    for (int i = 0; i <20 ; i++) {
            mB=BitmapFactory.decodeResource(getResources(), R.drawable.cloud_01);
            mB2=BitmapFactory.decodeResource(getResources(), R.drawable.cloud_01);
            mB3=BitmapFactory.decodeResource(getResources(), R.drawable.cloud_01);
    }
    Logger.d("fasfadsfad","load finish");
}


Bitmap InBitmap Sample:
@Override
public void onBackPressed() {
    for (int i = 0; i <20 ; i++) {
        if(mB==null){
            mB=BitmapFactory.decodeResource(getResources(), R.drawable.cloud_01);
        }else {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inMutable = true;
            options.inBitmap = mB;
            options.inSampleSize = 1;
            mB=BitmapFactory.decodeResource(getResources(), R.drawable.cloud_01,options);
        }

        if(mB2==null){
            mB2=BitmapFactory.decodeResource(getResources(), R.drawable.cloud_01);
        }else {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inMutable = true;
            options.inBitmap = mB2;
            options.inSampleSize = 1;
            mB2=BitmapFactory.decodeResource(getResources(), R.drawable.cloud_01,options);
        }

        if(mB3==null){
            mB3=BitmapFactory.decodeResource(getResources(), R.drawable.cloud_01);
        }else {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inMutable = true;
            options.inBitmap = mB3;
            options.inSampleSize = 1;
            mB3=BitmapFactory.decodeResource(getResources(), R.drawable.cloud_01,options);
        }
    }
    Logger.d("fasfadsfad","load finish");
}

 

在Android 2.2 (API level 8)及其以下版本上,垃圾回收线程工作时,APP线程就得暂停,这一特性无疑会降低APP的性能。 Android 2.3开始实现了并发垃圾回收,这意味着一个bitmap对象不再任何被引用持有时,它所占有的内存空间会很快的被回收。

 

在Android 2.3.3 (API level 10)及其以下版本上,bitmap的ARGB数据(backing pixel data)是存在native内存里的,而bitmap对象本身是存在Dalvik的堆里的。当bitmap对象不再被引用时,Dalvik的堆里的内存可以被垃圾回收期回收,但是native部分的内存却不会同

步被回收。如果需要频繁的加载很多bitmap到内存中,即使Java层已经及时的释放掉不用bitmap,依旧有可能引起OOM。幸运的是从Android 3.0 (API level 11)开始,bitmap的ARGB数据和bitmap对象一起存在Dalvik的堆里了。这样bitmap对象和它的ARGB数据就可以同步>回收了

不同Android版本对bitmap内存管理方式不同,我们应对症下药的来优化不同版本上bitmap的内存使用。

各版本区别:

1.Android 2.3.3 (API level 10)及其以下版本

在Android 2.3.3 (API level 10)及其以下版本上,Android开发文档推荐我们使用 recycle()方法。recycle()方法可以使APP尽可能快的回收bitmap所使用的native内存。

注意:recycle()方法是不可逆的,bitmap调用了recycle()之后就不能再使用了。使用recycle()之后的bitmap系统会抛出"Canvas: trying to use a recycled bitmap"的错误。所以调用recycle()方法之前一定要确认bitmap不会再使用了。

2.Android 3.0 (API level 11)及其以上版本

Android 3.0 开始引入了BitmapFactory.Options.inBitmap字段。如果设置了这个字段,bitmap在加载数据时可以复用这个字段所指向的bitmap的内存空间。新增的这种内存复用的特性,可以优化掉因旧bitmap内存释放和新bitmap内存申请所带来的性能损耗。但是,内存

能够复用也是有条件的。比如,在Android 4.4(API level 19)之前,只有新旧两个bitmap的尺寸一样才能复用内存空间。Android 4.4开始只要旧bitmap的尺寸大于等于新的bitmap就可以复用了。

示例:

private static boolean canUseForInBitmap(
        Bitmap candidate, BitmapFactory.Options targetOptions) {

    //4.4之前的版本,尺寸必须完全吻合
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
        return candidate.getWidth() == targetOptions.outWidth
                && candidate.getHeight() == targetOptions.outHeight
                && targetOptions.inSampleSize == 1;
    }
    //4.4版本,可以使用比自己大的bitmap
    int width = targetOptions.outWidth;
    int height = targetOptions.outHeight;/// (targetOptions.inSampleSize==0?1:targetOptions.inSampleSize)

    //根据图片格式,计算具体的bitmap大小
    int byteCount = width * height * getBytesPerPixel(targetOptions.inPreferredConfig); //candidate.getConfig()

    return byteCount <= candidate.getAllocationByteCount();
}

private static int getBytesPerPixel(Bitmap.Config config) {
    if (config == Bitmap.Config.ARGB_8888) {
        return 4;
    } else if (config == Bitmap.Config.RGB_565) {
        return 2;
    } else if (config == Bitmap.Config.ARGB_4444) {
        return 2;
    } else if (config == Bitmap.Config.ALPHA_8) {
        return 1;
    }
    return 1;
}
BitmapFactory.Options options = new BitmapFactory.Options();
Logger.d("dsfasfsad","canUseForInBitmap true ");
options.inMutable = true;
options.inBitmap = mBitmap;
options.inSampleSize = 1;//复用这里必须为1
mTwoBitmap = BitmapFactory.decodeResource(getResources(), mBitmapResourceIds[i],options);

3.待补充..

楼主在使用recycle回收bitmap时候,虽然已调用recycle方法但多次反复启动应用java内存还是会飙升,最终导致OOM,进行测试发现bitmap变为成员变量后,即使回收掉因为是强引用虚拟机还未来得及释放情况还是会占用虚拟机内存,故若成员变量场景使用软引用持有可有效释放虚拟机内存。

引用:

bitmap API说明 :  https://www.jianshu.com/p/7049aae916a2

https://developer.android.com/reference/android/graphics/BitmapFactory.Options

bitmap属性说明:https://www.jianshu.com/p/8206dd8b6d8b

bitmap复用说明:https://juejin.im/entry/57cd1c7cbf22ec006c2e2261

bitmap内存模型:https://www.jianshu.com/p/3f6f6e4f1c88

bitmap各版本变迁与调用时序分析:https://www.jianshu.com/p/d5714e8987f3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值