ImageLoader开源项目学习

2015-6-29

自打毕业入行就开始了android开发之旅,经历了两三个比较大型的项目。虽然说是大型项目,其实没有多大技术含量,只不过是项目的周期比较长久罢了。在做项目的过程中遇到过几个比较棘手的问题,内存管理就是其中之一。为此,也有牛人专门分享了几个开源框架供大家使用。其中比较流行的就有ImageLoader项目,上次还了解到facebook也开源了一个android图片库的项目叫Fresco。感叹牛人无私奉献的同时,也自省我为什么做不出这样大众化的产品或者框架呢?小说里面常讲成为武林高手,必先有武林秘笈,再通过勤学苦练方能做到。在我们软件行业呢,我认为这“武林秘笈”就是一个个优秀的开源项目。所以,要想成为软件大师,必先深入的研究学习这些项目的源码。以上只是个人的一些经历和看法,此际。



-------------------------我是分割线------------------------



通过ImageLoader项目的学习,希望能搞清楚一件事。那就是ImageLoader的缓存机制。

面试过程中,我问过很多人关于缓存机制的描述,没有一个是满意的。很多人会讲,bitmap不用的时候就回收。我觉得这个描述太浅显了,不足以形容一个机制!所以,通过此文希望能把这个缓存机制描述清楚。


第一个点:内存分配数量


我们都知道java虚拟机分配给每个进程的堆内存(heap limit)是有限的,android也是同样的原理。android当中,每个app的最大内存数跟设备内存是直接联系的。那么,我们实际设备的每个app的最大内存数量能是多少呢?可以通过以下方式获取查看(学习自com.nostra13.universalimageloader.core包下,DefaultConfigurationFactory类的createMemoryCache方法)

			//获取每个app的最大内存数
			ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
			int memoryClass = am.getMemoryClass();


并且在android3.0之后,manifest,application增加了一个属性largeHeap。这个设置可以帮助我们app获取更多的内存数量,可以通过以下方式查看

am.getLargeMemoryClass();


是不是又学了一招?实际效果还没有对比,如果你的程序经常内存溢出,不妨加这个设置试试看。


2015-6-30

补充上一点:经过测试largeMemoryClass最大可达到手机理论内存的1/4(测试型号s3、m8),大大提升了单个app的内存上限。


2015-7-2

第二个点:缓存是如何被及时回收的?


ImageLoader的缓存机制使用的双层缓存,即磁盘、内存缓存。这应该是成熟缓存机制的标配。那么,就先来看看磁盘缓存的文件回收机制吧!

首先,ImageLoader会约定两个数量上限(文件总大小、文件数)只要磁盘文件超过其中之一个上限,就会回收不常用的文件。

那么问题又来了,如何判定一个文件不常用呢?

答案是ImageLoader采用LRU策略(算法)来理本地磁盘文件。 LRULeast Recently Used的缩写,即最近最少使用页面置换算法。更详细的LRU策略解释这里不再展开。下面来看看具体实现细节:


LruDiskCache包含一个DiskLruCache的属性,LruDiskCache的接口实现都是依靠DiskLruCache来做的。所以DiskLruCache类里面才是磁盘缓存处理的核心类。DiskLruCache这个类里面有一个File属性journalFile是用来记录文件最近访问先后顺序的。lruEntries属性存放所有磁盘缓存文件的路径和文件大小。lruEntries的定义如下:

	//这是lru算法的关键所在,以元素最近访问的先后顺序来排序。最近访问的时间距离现在越久则越靠前,否则越靠后
	private final LinkedHashMap<String, Entry> lruEntries =
			new LinkedHashMap<String, Entry>(0, 0.75f, true);

第三个参数true就是指按着最经访问顺序来排序。

磁盘缓存就记录这么多,接下来是内存缓存。相信其原理也是类似的。

2015-7-3

本来想内存缓存可能会用到非常巧妙的方法来处理内存的回收问题。查看到结果,有些诧异呢!内存缓存原理:

1、根据url从内存缓存找Bitmap对象,找到返回,否则执行下一步

2、从网络或者磁盘文件读取到Bitmap对象,直接放在一个map容器(使用LRU策略管理)缓存起来并返回。

3、如果容器内的所有Bitmap对象大小超过内存缓存上限maxSize,则remove掉距离当前最久访问的Bitmap对象。(这里就是我说的诧异点,竟然不做recycle操作)

下面是内存缓存管理的类图:



trimToSize方法就是根据内存缓存上限管理的实现。可以看到这里被remove掉的Bitmap对象并没有做recycle操作,而仅仅是被抛弃为垃圾对象等待系统回收,这样还是会留下OOM的隐患。实际上在这里直接做recycle操作是有些鲁莽的,因为这个Bitmap对象很有可能正在被某个view使用中。如果强行recycle,就会报这样一个错:java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap。

以上是ImageLoader项目采用的默认缓存策略,该项目还支持FIFO(先进先出)、LimitedAge(最大存储周期)==缓存机制,这里不再做详细记录。缓存的内容就记录这些。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值