Fresco是Facebook出品的高性能图片加载库,号称在所有图片加载库中是效率、性能最好的。Fresco整个库还挺大的,还有native层。这里不对Fresco做深入分析,只关注Fresco在Android Bitmap的管理上采用了哪些黑科技
Java Heap(Dalvik Heap),这部分的内存区域是由Dalvik虚拟机管理,通过Java中 new
关键字来申请一块新内存。这块区域的内存是由GC直接管理,能够自动回收内存。这块内存的大小会受到系统限制,当内存超过APP最大可用内存时会OOM
Native Heap,这部分内存区域是在C++中申请的,它不受限于APP的最大可用内存限制,而只是受限于设备的物理可用内存限制。它的缺点在于没有自动回收机制,只能通过C++语法来释放申请的内存
Ashmem(Android匿名共享内存),这部分内存类似于Native内存区,但是它是受Android系统底层管理的,当Android系统在内存不足时,会回收Ashmem区域中状态是 unpin
的对象内存块,如果不希望对象被回收,可以通过 pin
来保护一个对象
Ashmem一般在应用层中是无法直接访问的,除了几个特例之外。其中之一就是 decode bitmap ,我们可以通过设置 BitmapFactory.Optinons.inPurgeable = true
来创建一个 Purgeable Bitmap ,这样decode出来的bitmap是在Ashmem内存中,GC无法自动回收它。当该Bitmap在被使用时会被 pin 住,使用完之后就 unpin ,这样系统就可以在将来某一时间释放这部分内存。
如果一个 unpinned 的bitmap在之后又要被使用,系统会运行时又将它重新decode,但是这个decode操作是发生在UI线程中的有可能会造成掉帧现象,因此改做法已经被Google废弃掉,转为鼓励使用 inBitmap
来告知bitmap解码器去尝试使用已经存在的内存区域,新解码的bitmap会尝试去使用之前那张bitmap在heap中所占据的pixel data内存区域,而不是去问内存重新申请一块区域来存放bitmap。利用这种特性,即使是上千张的图片,也只会仅仅只需要占用屏幕所能够显示的图片数量的内存大小。
但是使用 inBitmap
需要注意几个限制条件:
为了让inPurgeable的bitmap不被自动 unpinned ,可以通过使用jni函数 AndroidBitmap_lockPixels()
函数来强制 pin bitmap ,这样我们就可以在bitmap被使用时不会被系统自动 unpinned ,从而也就避免了 unpinned 的bitmap在重新被使用时又会被重新decode而引起的掉帧问题。同样的,Android也提供了 AndroidBitmap_unlockPixels()
来让bitmap重新变为 unpinned 状态,这样系统在内存不足时就可自动回收这部分内存
Facebook tricks for image handling in Android
Introducing Fresco: A new image library for Android
Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析原创不易,欢迎转载,但还请注明出处:blog.waynell.com