fresco是facebook主导的一个开源图片缓存库,从它提供的示例程序comparison来看,fresco貌似比其他的几个目前android主流的图片缓存库(glide,picasso,uil等)更快更节省内存。接下来就看看它到底是如何做到的。注:本文分析基于0.8.1版本。
背景知识
- lru与SoftReference那些年的爱恨情仇:很久很久以前,android的内存缓存还用SoftReference,在2.3以后,垃圾回收机制被修改,软引用已不推荐用作缓存技术了,lru等才是正义。既然软引用已经不再推荐使用,为毛还要提到它呢?因为freso偏偏用到了它!
- dalvik vm heap和native heap:heap即为堆,malloc、new等函数(方法)都是从堆申请内存空间,这点不用多解释。两个heap的区别在于,java操作的是dvm的heap,native代码使用malloc操作的是native heap。而dvm对heap的大小是有限制的,如果超过了这个限制,就会抛出OOM异常。这也是OOM异常的由来。于是fresco就会在native层申请内存来代替部分java层的内存。
- ashmem:匿名共享内存,前面提到fresco会用native申请内存空间,ashmem就是其中的一种。ashmem通过pin、unpin操作内存块,被unpinned的内存会放在一个lru列表,当内核空间不足时调用ashmem注册的回调来清理内存。具体介绍可参考Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析 。
- Bitmap:关于Bitmap的使用技巧很多,官方有详细的文档,这里只提一下fresco用到的部分内容。
inBitmap,传入一个Bitmap给BitmapFactory复用,减少申请内存。关于不同版本对inBitmap的大小限制见官方文档,fresco取的是大小一致的,能满足最严格的条件。
inTempStorage,在BitmapFactory对流进行解码时会分配一段临时的缓冲,如果不传入的话,每次解码都会重新申请,官方建议是16k。
inPurgeable,根据官方文档,如果这个参数被设置为true,Bitmap会创建一段pixels空间,当系统需要回收时,这段空间就会被清除。在这种情况下,如果需要重新访问这段空间,Bitmap就会重新对未编码的数据进行编码。这未编码数据的保存方式可持有它的引用或进行一次全拷贝,由inInputShareable参数控制。这两个参数都仅限lollipop以下版本使用。这个参数具体是如何影响内存管理的,涉及到skia的具体实现,从BitmapFactory的相关代码来看,貌似也用到了ashmem,有兴趣的可自行研究。
inJustDecodeBounds,这个参数应该比较常见了,一般用在对图片压缩。如果直接对一张大尺寸的图片进行解码,