Android高级开发工程师面试系列-如何对图片进行缓存?

面试题:如何对图片进行缓存?

题目剖析:
1.网络、磁盘,内存缓存
2.缓存算法分析
3.以熟悉的框架为例分析它的缓存机制
4.要有验证算法效果的意识

一.图片加载过程
先从内存中读取,如果没有从磁盘中读取,如果没有从网络获取显示
在这里插入图片描述
二.缓存算法分析
设计缓存算法,需要考虑以下几点:
1.哪些应该保存?
获取成本,缓存成本,缓存的价值
首先看获取的成本高不高,获取成本高,缓存就非常值,其次看缓存成本,本身缓存内存就很小,如果缓存的文件是个1个g的,缓存就非常不值了,最后随着时间的推移,如果缓存的文件使用率不高,那缓存的价值就不高。

2.哪些应该丢弃?什么时候丢弃?
一、LRU算法:
这个时候我们的LRU算法就登场了(最近最少使用算法),LRU算法的工作流程:假设我们设计的只能缓存4个,通过以下演算看下LRU的缓存流程:
1.访问顺序:A→B→D
缓存媒介:D→B→A
2.访问顺序:A→B→D→D
缓存媒介:D→B→A
3.访问顺序:A→B→D→D→BA→B→D→D→B
缓存媒介:B→D→A
4.访问顺序:A→B→D→D→B→C
缓存媒介:C→B→D→A
5.访问顺序:A→B→D→D→B→C→A
缓存媒介:A→C→B→D
6.访问顺序:A→B→D→D→B→C→A→E
缓存媒介:E→A→C→B
整个缓存的流程分为以上六步:
LruCache(Least Recently Used)算法的核心思想就是最近最少使用算法。他在算法的内部维护了一个LinkHashMap的链表,通过put数据的时候判断是否内存已经满了,如果满了,则将最近最少使用的数据给剔除掉,从而达到内存不会爆满的状态。我们发现经过以上几步缓存之后,缓存内容D被干掉了。
这里有一个疑问,为什么LruCache内部原理的实现需要用到LinkHashMap来存储数据呐?
因为LinkHashMap内部是一个数组加双向链表的形式来存储数据,他能够保证插入时候的数据和取出来的时候数据的顺序的一致性。也就是说,我们以什么样的顺序插入数据,就会以什么样的顺序取出数据。并且更重要的一点是,当我们通过get方法获取数据的时候,这个获取的数据会从队列中跑到队列头来,从而很好的满足我们LruCache的算法设计思想。
我们先看下LruCache算法的构造方法。
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException(“maxSize <= 0”);
}
this.maxSize = maxSize;
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
从构造方法的源码我们可以看到,在这段代码中我们主要做了两件事。第一是判断下传递来的最大分配内存大小是否小于零,如果小于零则抛出异常,因为我们如果传入一个小于零的内存大小就没有意义了。之后在构造方法内存就new了一个LinkHashMap集合,从而得知LruCache内部实现原理果然是基于LinkHashMap来实现的,这里需要注意new LinkedHashMap<K, V>(0, 0.75f, true);时最后一个吃参数传的true,通过源码我们发现当为true时,当内存不足时,LinkedHashMap会自动删除最后一个元素。

二、LFU算法(最近不经常使用原则):
如果用LFU算法来实现上面的缓存流程,则到最后缓存中的内容应该为E→D→B→A,我们发现最后把C给丢弃了,因为LFU遵循最近不经常使用原则,也就是说使用次数最少的,当内存不足时会首先被干掉。
我们熟悉的Glide图片加载框架就是使用LRUCache算法,内部也是基于LinkedhashMap来实现的。

总结:当面试时面试官问图片的缓存机制时,我们可以以Glide为例说下图片的加载过程,解释下LRUCache算法缓存原理以及内部基于LinkHashMap来实现的原因。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章