Android LRuCache 캐 시 정책 에 대한 간단 한 설명
일반적으로 캐 시 정책 은 캐 시 추가,가 져 오기,삭제 등 세 가지 작업 을 포함한다.캐 시 를 어떻게 추가 하고 가 져 오 는 지 이해 하기 쉽 습 니 다.그런데 왜 캐 시 를 삭제 해 야 합 니까?메모리 캐 시 든 하 드 디스크 캐 시 든 캐 시 크기 가 제한 되 어 있 기 때문이다.캐 시가 가득 찬 후에 캐 시 를 추가 하려 면 오래된 캐 시 를 삭제 하고 새 캐 시 를 추가 해 야 합 니 다.
따라서 LRU(Least Recently Used)캐 시 알고리즘 이 생 겨 났 다.LRU 는 최근 에 가장 적 게 사용 하 는 알고리즘 으로 캐 시가 가득 찼 을 때 최근 에 가장 적 게 사용 하 는 캐 시 대상 을 우선 도태 시 키 는 것 이 핵심 이다.LRU 알고리즘 을 사용 한 캐 시 는 두 가지 가 있 습 니 다.LRhcache 와 DisLRuCache 는 각각 메모리 캐 시 와 하 드 디스크 캐 시 를 실현 하 는 데 사 용 됩 니 다.그 핵심 사상 은 모두 LRU 캐 시 알고리즘 입 니 다.
2.LruCache 의 사용
루 캐 시 는 안 드 로 이 드 3.1 에서 제공 하 는 캐 시 클래스 이기 때문에 안 드 로 이 드 에 서 는 루 캐 시 를 직접 사용 해 메모리 캐 시 를 구현 할 수 있다.한편,DisLRuCache 는 현재 Android 에서 Android SDK 의 일부분 이 아니 지만 Android 공식 문 서 는 이 알고리즘 을 사용 하여 하 드 디스크 캐 시 를 실현 하 는 것 을 추천 합 니 다.
1.루 카 셰 의 소개
LruCache 는 일반적인 유형 으로 최근 에 사용 한 대상 을 강 한 인용(즉,우리 가 평소에 사용 하 는 대상 참조 방식)으로 LinkedHashMap 에 저장 하 는 것 이 주요 알고리즘 원리 이다.캐 시 가 가득 찼 을 때 최근 에 가장 적 게 사용 한 대상 을 메모리 에서 제거 하고 get 과 put 방법 을 제공 하여 캐 시 가 져 오기 와 추가 작업 을 완성 합 니 다.
2.LruCache 사용
LruCache 의 사용 은 매우 간단 합 니 다.그림 캐 시 를 예 로 들 었 습 니 다.
int maxMemory = (int) (Runtime.getRuntime().totalMemory()/1024);
int cacheSize = maxMemory/8;
mMemoryCache = new LruCache<String,Bitmap>(cacheSize){
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes()*value.getHeight()/1024
;
}
① 현재 프로 세 스 가 사용 할 수 있 는 용량 의 8 분 의 1 크기 로 LruCache 캐 시 크기 를 설정 합 니 다.② size Of 를 다시 쓰 는 방법 으로 캐 시 할 그림 의 크기 를 계산 합 니 다.
메모:캐 시 총 용량 은 캐 시 대상 의 크기 에 사용 되 는 단위 와 일치 해 야 합 니 다.
3.LruCache 의 실현 원리
LruCache 의 핵심 사상 은 이해 하기 쉽 습 니 다.캐 시 대상 목록 을 유지 하 는 것 입 니 다.그 중에서 대상 목록 의 배열 방식 은 방문 순서에 따라 이 루어 집 니 다.즉,방문 하지 않 은 대상 은 팀 의 끝 에 두 고 곧 도 태 될 것 입 니 다.최근 방문 대상 은 팀 에 두 고 탈락 한다.
다음 그림 에서 보 듯 이:
그렇다면 이 대기 열 은 누가 지 키 는 것 일 까?앞서 링크 드 하 쉬 맵 이 지 키 는 것 을 소개 했다.한편,링크 드 하 쉬 맵 은 배열+양 방향 링크 의 데이터 구조 로 이 루어 진다.그 중에서 양 방향 링크 의 구 조 는 방문 순서 와 삽입 순 서 를 실현 하여 링크 드 HashMap 의 쌍 을 일정한 순서에 따라 배열 할 수 있다.
아래 구조 함 수 를 통 해 링크 드 HashMap 의 양 방향 링크 구 조 를 방문 순서 로 지정 합 니까?삽입 순서 로 지정 합 니까?
public LinkedHashMap(int initialCapacity,float loadFactor,boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
그 중에서 accessOrder 는 true 로 설정 하면 방문 순서 이 고 false 이 며 삽입 순서 입 니 다.구체 적 인 예 로 설명:true 로 설정 되 었 을 때
public static final void main(String[] args) {
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.put(4, 4);
map.put(5, 5);
map.put(6, 6);
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 4:4 5:5 6:6 1:1 2:2최근 에 방문 한 마지막 출력 이 라면 LRU 캐 시 알고리즘 에 딱 맞 는 생각 입 니 다.이 를 통 해 알 수 있 듯 이 루 캐 시가 교묘 하 게 실현 한 것 은 바로 링크 드 하 쉬 맵 의 이러한 데이터 구 조 를 이용 한 것 이다.
다음은 LruCache 소스 코드 에서 LinkedHashMap 을 어떻게 사용 하여 캐 시 추가,획득,삭 제 를 실현 하 는 지 구체 적 으로 살 펴 보 겠 습 니 다.
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);
}
LruCache 의 구조 함수 에서 바로 LinkedHashMap 의 접근 순 서 를 사용 한 것 을 볼 수 있 습 니 다.put()방법:
public final V put(K key, V value) {
// ,
if (key == null || value == null) {
throw new NullPointerException("key == null || value== null");
}
V previous;
synchronized (this) {
// 1
putCount++;
//
size += safeSizeOf(key, value);
// map
previous = map.put(key, value);
// ,
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
//entryRemoved() ,
if (previous != null) {
entryRemoved(false, key, previous, value);
}
// ( )
trimToSize(maxSize);
return previous;
}
put()방법 은 어 려 운 점 이 없 음 을 알 수 있 습 니 다.중요 한 것 은 캐 시 대상 을 추가 한 후 trimToSize()방법 을 사용 하여 캐 시가 가득 찼 는 지 여 부 를 판단 하 는 것 입 니 다.가득 차 면 최근 에 가장 적 게 사용 하 는 알고리즘 을 삭제 해 야 합 니 다.trimToSize()방법:
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 || map.isEmpty()) {
break;
}
// , ,
Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
key = toEvict.getKey();
value = toEvict.getValue();
// ,
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}
trimToSize()방법 은 캐 시 크기 가 최대 치 보다 작 을 때 까지 링크 드 HashMap 의 끝 요 소 를 계속 삭제 합 니 다.LruCache 의 get()방법 을 호출 하여 집합 에 있 는 캐 시 대상 을 가 져 올 때 이 요 소 를 한 번 방문 한 것 을 의미 합 니 다.대기 열 을 업데이트 하고 전체 대기 열 을 방문 순서에 따라 정렬 합 니 다.이 업데이트 과정 은 링크 드 HashMap 의 get()방법 에서 이 루어 졌 습 니 다.
LruCache 의 get()방법 먼저 보기:
public final V get(K key) {
//key
if (key == null) {
throw new NullPointerException("key == null");
}
V mapValue;
synchronized (this) {
//
//get()
mapValue = map.get(key);
if (mapValue != null) {
hitCount++;
return mapValue;
}
missCount++;
}
그 중에서 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;
}
recordAccess()를 호출 하 는 방법 은 다음 과 같 습 니 다.
void recordAccess(HashMap<K,V> m) {
LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
//
if (lm.accessOrder) {
lm.modCount++;
//
remove();
//
addBefore(lm.header);
}
}
이 를 통 해 알 수 있 듯 이 LruCache 에서 집합 LinkedHashMap 을 유지 하고 있 습 니 다.이 LinkedHashMap 은 방문 순서 로 정렬 되 어 있 습 니 다.put()방법 을 호출 할 때 결합 에 요 소 를 추가 하고 trimToSize()를 호출 하여 캐 시가 가득 찼 는 지 여 부 를 판단 합 니 다.가득 차 면 링크 드 HashMap 의 교체 기 를 사용 하여 팀 의 꼬리 요 소 를 삭제 합 니 다.즉,최근 에 가장 적 게 접근 한 요 소 를 삭제 합 니 다.get()방법 으로 캐 시 대상 에 접근 할 때 링크 드 HashMap 의 get()방법 으로 해당 하 는 집합 요 소 를 얻 고 이 요 소 를 팀 헤드 로 업데이트 합 니 다.이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 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에 따라 라이센스가 부여됩니다.