Android 캐 시 메커니즘-LruCache 의 상세 한 설명
LruCache 의 핵심 원 리 는 바로 LinkedHashMap 에 대한 효과 적 인 이용 이다.그 내부 에 LinkedHashMap 구성원 변수 가 존재 하 는데 주의해 야 할 4 가지 방법 은 구조 방법,get,put,trimToSize 이다.
LRU(Least Recently Used)캐 시 알고리즘 이 생 겨 났 습 니 다.LRU 는 최근 에 가장 적 게 사용 하 는 알고리즘 입 니 다.캐 시가 가득 찼 을 때 최근 에 가장 적 게 사용 하 는 캐 시 대상 을 우선 도태 시 키 는 것 이 핵심 입 니 다.LRU 알고리즘 을 사용 한 캐 시 는 두 가지 가 있 습 니 다.LRhcache 와 DisLRuCache 는 각각 메모리 캐 시 와 하 드 디스크 캐 시 를 실현 하 는 데 사 용 됩 니 다.그 핵심 사상 은 모두 LRU 캐 시 알고리즘 입 니 다.
LRU 원리
LruCache 의 핵심 사상 은 캐 시 대상 목록 을 유지 하 는 것 입 니 다.그 중에서 대상 목록 의 배열 방식 은 방문 순서에 따라 이 루어 집 니 다.즉,방문 하지 않 은 대상 은 팀 머리 에 두 고 곧 도 태 될 것 입 니 다.최근 방문 대상 은 팀 뒤에 두 고 탈락 한다.파티 끝 에 요 소 를 추가 하고,파티 헤드 에서 요 소 를 삭제 합 니 다)
LruCache 는 사실 링크 드 HashMap 양 방향 링크 구 조 를 사 용 했 으 며,현재 링크 드 HashMap 의 사용 방법 을 분석 하고 있다.
1.구조 방법:
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
accessOrder 가 true 일 때 이 집합 요소 의 순 서 는 방문 순서 입 니 다.즉,방문 한 후에 이 요 소 를 집합 맨 뒤에 두 는 것 입 니 다.예 를 들 면:
LinkedHashMap < Integer, Integer > map = new LinkedHashMap < > (0, 0.75f, true);
map.put(0, 0);
map.put(1, 1);
map.put(2, 2);
map.put(3, 3);
map.get(1);
map.get(2);
for (Map.Entry < Integer, Integer > entry: map.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
출력 결과:0:0
3:3
1:1
2:2
다음은 LruCache 소스 코드 에서 LinkedHashMap 을 어떻게 사용 하여 캐 시 추가,획득,삭 제 를 실현 하 는 지 구체 적 으로 살 펴 보 겠 습 니 다.
/**
* @param maxSize for caches that do not override {@link #sizeOf}, this is
* the maximum number of entries in the cache. For all other caches,
* this is the maximum sum of the sizes of the entries in this cache.
*/
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);//accessOrder true
}
LruCache 의 구조 함수 에서 바로 LinkedHashMap 의 접근 순 서 를 사용 한 것 을 볼 수 있 습 니 다.2.puut()방법
/**
* Caches {@code value} for {@code key}. The value is moved to the head of
* the queue.
*
* @return the previous value mapped by {@code key}.
*/
public final V put(K key, V value) {
if (key == null || value == null) {// ,
throw new NullPointerException("key == null || value == null");
}
V previous;
synchronized (this) {
putCount++;// 1
size += safeSizeOf(key, value);//
previous = map.put(key, value);// map
if (previous != null) {// ,
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {//entryRemoved() ,
entryRemoved(false, key, previous, value);
}
trimToSize(maxSize);// ( )
return previous;
}
put()방법 을 볼 수 있 습 니 다.중요 한 것 은 캐 시 대상 을 추가 한 후에 trimToSize()방법 으로 메모리 가 max Size 를 초과 하지 않도록 하 는 것 입 니 다.3.trimToSize 방법
trimToSize()방법 다시 보기:
/**
* Remove the eldest entries until the total of remaining entries is at or
* below the requested size.
*
* @param maxSize the maximum size of the cache before returning. May be -1
* to evict even 0-sized elements.
*/
public void trimToSize(int maxSize) {
while (true) {//
K key;
V value;
synchronized (this) {
// map size 0 size 0,
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName()
+ ".sizeOf() is reporting inconsistent results!");
}
// size , map , ,
if (size <= maxSize) {
break;
}
// map
Map.Entry<K, V> toEvict = map.eldest();
if (toEvict == null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}
trimToSize()방법 은 캐 시 크기 가 최대 치 보다 작 을 때 까지 링크 드 HashMap 의 헤더 요 소 를 계속 삭제 합 니 다.4.get 방법
LruCache 의 get()방법 을 호출 하여 집합 에 있 는 캐 시 대상 을 가 져 올 때 이 요 소 를 한 번 방문 한 것 을 의미 합 니 다.대기 열 을 업데이트 하고 전체 대기 열 을 방문 순서에 따라 정렬 합 니 다.이 업데이트 과정 은 링크 드 HashMap 의 get()방법 에서 이 루어 졌 습 니 다.
이어서 LuCache 의 get()방법 을 보도 록 하 겠 습 니 다.
/**
* Returns the value for {@code key} if it exists in the cache or can be
* created by {@code #create}. If a value was returned, it is moved to the
* head of the queue. This returns null if a value is not cached and cannot
* be created.
*/
public final V get(K key) {
if (key == null) {//key
throw new NullPointerException("key == null");
}
V mapValue;
synchronized (this) {
/
mapValue = map.get(key);
if (mapValue != null) {
hitCount++;
return mapValue;
}
missCount++;
}
LruCache 를 보 는 get 방법 은 실제 LinkedHashMap 의 get 방법 을 호출 한 것 입 니 다.
public V get(Object key) {
LinkedHashMapEntry<K,V> e = (LinkedHashMapEntry<K,V>)getEntry(key);
if (e == null)
return null;
e.recordAccess(this);//
return e.value;
}
그리고 링크 드 Hash MapEntry 의 recordAccess 방법 을 살 펴 보 겠 습 니 다.
/**
* This method is invoked by the superclass whenever the value
* of a pre-existing entry is read by Map.get or modified by Map.set.
* If the enclosing Map is access-ordered, it moves the entry
* to the end of the list; otherwise, it does nothing.
*/
void recordAccess(HashMap<K,V> m) {
LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
if (lm.accessOrder) {//
lm.modCount++;
remove();//
addBefore(lm.header);//
}
}
recordAccess 방법의 역할 은 accessOrder 가 true 라면 존재 하 는 entry 를 get 에서 읽 거나 set 편집 을 한 후에 팀 끝으로 옮 기 는 것 입 니 다.그렇지 않 으 면 어떠한 조작 도 하지 않 습 니 다.즉,이 방법의 작용 은 방금 방문 한 원 소 를 집합의 마지막 자리 에 놓 는 것 이다
요약:
루 캐 시의 핵심 원 리 는 링크 드 하 쉬 맵 대상 을 효과적으로 활용 하 는 것 이다.구조 방법 에서 max Size 를 설정 하고 accessOrder 를 true 로 설정 합 니 다.get 을 실행 하면 방문 요 소 를 대기 열 끝 에 두 고 put 작업 을 한 후에 trimToSize 를 호출 하여 LinkedHashMap 의 크기 가 max Size 보다 크 지 않 습 니 다.
위 에서 말 한 것 은 편집장 이 여러분 에 게 소개 한 안 드 로 이 드 캐 시 메커니즘 인 LruCache 의 상세 한 통합 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 저 에 게 메 시 지 를 남 겨 주세요.편집장 은 신속하게 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.