[Android] Bitmap内存在各系统版本的演化

本文聚焦的问题
1、Bitmap的像素数据是存在哪里的?
2、Bitmap内存如何释放?需要调用recycle吗?

Bitmap bitmap = Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888);

以这样声明一个bitmap为例,有三个位置需要关注,bitmap引用本身所在的位置(栈),引用指向的对象所在的位置(堆),对象中持有的像素数据所在的位置,像素数据在不同系统版本所在的位置略有不同,导致bitmap所占用的内存的释放方式也有所不同。


Android1.0~Android2.3

这几个版本Bitmap的像素数据是分配在Native内存中的,bitmap对象在Dalvik堆中占用的数据是很小的,只有width、height、config和指向堆的引用,这样的结果是bitmaps don’t get monitored well by the GC (it thinks they are the size of a reference),所以GC无法知道当前的内存情况是否乐观,大量创建bitmap可能不会触发到GC,而Native中bitmap的像素数据可能已经占用了过多内存,这时候就会OOM,所以推荐在bitmap使用完之后,调用recycle释放掉Native的内存。


Android3.0~Android7.1

这几个版本,Bitmap的数据结构发生了改变,其中多了如下属性,用来存储像素数据,

private byte[] mBuffer;

至此像素数据就和bitmap对象一起都分配在堆中了,一起接受GC管理,只要bitmap置为null没有被强引用持有,GC就会把它回收掉,和普通对象一样。

Android8.0+

这里开始,Bitmap的像素数据又重新回到native分配了,Bitmap数据结构中

private byte[] mBuffer;这个属性不见了,取而代之的是private final long mNativePtr;,其指向的是native的内存地址。为什么呢?

安卓的每个APP都是运行在单独的虚拟机中的,系统同时会有多个APP同时运行,所以分给每个虚拟机内存上限不会太高,一般也就几百M,虚拟机启动时内存上限就是定值,一旦达到内存上限,就会OOM。

但是安卓手机的可用内存普遍已经4、6、8个G,大多数情况下系统还是有剩余内存可用的(其他APP远没有达到自己虚拟机内存上限的情况下),而一个APP中占用内存最多的一般都是Bitmap,所以如果能把系统空余内存空间利用起来,就能大大增加当前APP的可用内存,而把bitmap的像素数据放到native就能解决这个问题,native可以直接使用整个linux系统的内存,不受当前APP所在虚拟机的内存上限控制,这样就可以持续使用内存,直到用完系统的空余内存。这样的坏处是一旦发生OOM,不会被系统的UncaughtExceptionHandler捕获,会直接crash。

不过借鉴之前经验,Bitmap引入了NativeAllocationRegistry这样一种辅助自动回收native内存的机制,依然不需要用户主动回收了,当bitmap的Java对象被回收后,NativeAllocationRegistry辅助回收这个对象所申请的native内存。


参考

Android Bitmap变迁与原理解析(4.x-8.x)

©️2020 CSDN 皮肤主题: 成长之路 设计师: Amelia_0503 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值