一、inBitmap:Bitmap复用的核心
inBitmap 是 Android 提供的原生 Bitmap 复用机制。通过在 BitmapFactory.Options 中设置一个可复用的 Bitmap 对象,可以显著减少内存分配和 GC 次数。
1. 复用条件
- Android 4.4+ :被复用的
Bitmap内存大小需大于等于新Bitmap。同时,像素格式必须兼容,例如ARGB_8888可以复用RGB_565的内存,但反之则不行。 - Android 3.0-4.3:复用的
Bitmap必须与目标Bitmap尺寸完全一致,且像素格式也必须完全匹配。
2. 复用失败与异常
如果 inBitmap 的复用条件不满足,BitmapFactory.decodeXXX() 将会抛出 IllegalArgumentException,并附带详细的错误信息。
二、底层原理:Skia与内存分配器
Bitmap 的内存复用,其底层实现依赖于 Android 的图形渲染引擎 Skia 和内存分配器。
1. 内存分配
Java层:Bitmap对象本身位于Java堆。Native层:Bitmap的像素数据位于Native堆。- Android 8.0+ :大部分
Bitmap像素数据直接存储在GPU内存中,进一步减少了CPU和GPU之间的数据传输。
2. 复用校验
- 在
Native层,BitmapFactory.cpp的canReuseBitmap()函数负责校验复用条件。 - 它会检查待复用
Bitmap的内存大小和像素格式,确保其满足复用要求。
三、最佳实践:使用BitmapPool管理复用
直接使用 inBitmap 会导致代码复杂,且容易出错。最佳实践是使用 BitmapPool 来管理可复用的 Bitmap 集合。
1. BitmapPool
- 作用:
BitmapPool是一个用于缓存和管理可复用Bitmap的内存池。 - 实现:
Glide的LruBitmapPool是一个经典的实现。它基于 LRU 策略,按Bitmap的尺寸和配置分组,从而实现高效的查找和复用。
2. recycle()与BitmapPool
recycle():调用Bitmap.recycle()会释放Native内存,并将Bitmap标记为已回收。已回收的Bitmap无法被复用。BitmapPool:BitmapPool接收的是未调用recycle()的Bitmap。当一个Bitmap不再被使用时,BitmapPool会将其缓存起来,而不是立即释放内存。
结论:
Bitmap 的复用是 Android 内存优化的核心。通过 inBitmap 属性,结合不同 API 版本的兼容性,我们可以实现高效的内存复用。在实践中,使用 BitmapPool 等工具管理可复用的 Bitmap,能有效避免 OOM 和 GC 带来的性能问题。