大家好,又见面了,我是全栈君。
本文聚焦的问题
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)
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/121303.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...