LinkedHashMap 최고의 실천: LruCache
13804 단어 메모리그림 캐 시LruCache안 드 로 이 드 캐 시
소스 코드 해독
OK 옛 규칙, 제 가 먼저 여러분 을 데 리 고 LruCache 의 소스 코드 를 연구 하 겠 습 니 다. 우 리 는 get, put, Remove 등 방법 을 중점적으로 보 겠 습 니 다. 사실은 원 리 는 바로 LinkedHashMap 의 체제 입 니 다.
public class LruCache<K, V> {
private final LinkedHashMap<K, V> map;// LinkedHashMap
private int size;//
private int maxSize;//
private int putCount;// put
private int createCount;// create
private int evictionCount;//
private int hitCount;//
private int missCount;//
/** * LruCache * @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) {// maxSize 1/8
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
/** * Sets the size of the cache. * @param maxSize The new maximum size. */
public void resize(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
synchronized (this) {
this.maxSize = maxSize;
}
trimToSize(maxSize);
}
/** * 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) {
throw new NullPointerException("key == null");
}
V mapValue;
synchronized (this) {
mapValue = map.get(key);
if (mapValue != null) {
hitCount++;
return mapValue;
}
missCount++;
}
/* * Attempt to create a value. This may take a long time, and the map * may be different when create() returns. If a conflicting value was * added to the map while create() was working, we leave that value in * the map and release the created value. */
V createdValue = create(key);
if (createdValue == null) {
return null;
}
synchronized (this) {
createCount++;
mapValue = map.put(key, createdValue);
if (mapValue != null) {
// There was a conflict so undo that last put
map.put(key, mapValue);
} else {
size += safeSizeOf(key, createdValue);
}
}
if (mapValue != null) {
entryRemoved(false, key, createdValue, mapValue);
return mapValue;
} else {
trimToSize(maxSize);
return createdValue;
}
}
/** * 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++;
size += safeSizeOf(key, value);
previous = map.put(key, value);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
//
entryRemoved(false, key, previous, value);
}
//
trimToSize(maxSize);
return previous;
}
/** * , * 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) {
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName()
+ ".sizeOf() is reporting inconsistent results!");
}
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);
}
}
/** * * Removes the entry for {@code key} if it exists. * @return the previous value mapped by {@code key}. */
public final V remove(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
V previous;
synchronized (this) {
previous = map.remove(key);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, null);
}
return previous;
}
……
}
위 에 있 는 LruCache 초기 화 할당 캐 시 크기 가 얼마나 되 는 지 아래 의 몇 가지 요 소 를 참고 할 수 있 습 니 다.
기본 사용
Cache 는 콘 텐 츠 의 수 를 제한 하기 위해 강 한 인용 을 저장 합 니 다. 아 이 템 이 방문 할 때마다 이 아 이 템 은 대기 열의 머리 로 이동 합 니 다.cache 가 가득 찼 을 때 새 아 이 템 을 추가 하면 대기 열 끝 에 있 는 아 이 템 을 회수 합 니 다.
int cacheSize = 4 * 1024 * 1024; // 4MiB
LruCache bitmapCache = new LruCache(cacheSize) {
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
}
그림 을 저장 할 4M 크기 의 저장 공간 을 만 듭 니 다. 대기 열 형식 으로 저장 한 다음 에 저 장 된 것 과 최근 에 사 용 된 것 은 대기 열의 마지막 에 놓 습 니 다. 이렇게 오래된 데 이 터 는 대기 열의 시작 에 놓 여 GC 회수 에 사 용 됩 니 다.
synchronized (cache) {
if (cache.get(key) == null) {
cache.put(key, value);
}}
이 방법 은 LruCache 가 저장 한 데 이 터 를 어떻게 규범화 하고 가 져 오 는 지 보 여 줍 니 다. 이 종 류 는 스 레 드 가 안전 하기 때문에 동기 블록 을 추가 하여 데 이 터 를 저장 하고 get 과 put 방식 으로 데 이 터 를 액세스 해 야 합 니 다. 이 점 은 Map 과 일치 합 니 다. put 시 키 가 같 으 면 데 이 터 를 덮어 씁 니 다.하지만 여기 키 와 value 가 비어 있 으 면 안 되 는 점 을 주의해 야 합 니 다. 여 기 는 맵 과 차이 가 있 습 니 다. 또한 자원 을 주동 적 으로 방출 해 야 합 니 다. 만약 에 cache 의 특정한 값 이 명확 하 게 방출 되 고 재 작성 방법 이 필요 하 다 면 주의해 야 합 니 다.
entryRemoved (boolean evicted, K key, V oldValue, V newValue)
자원 이 시스템 에서 회수 되 었 다 면 evicted 는 TRUE 로 되 돌아 갑 니 다. put, remove 방식 으로 회수 되 었 다 면 evicted 는 FALSE 로 되 돌아 갑 니 다. 그 다음 에 put 를 통 해 인지 reove 를 통 해 인지, new Value 가 비어 있 는 지 여 부 를 판단 할 수 있 습 니 다. 비어 있 으 면 put 호출 한 다음 에 reove 와 시스템 을 회수 할 때 자원 을 비 워 두 면 스스로 실현 해 야 합 니 다. 키 에 해당 하 는 아 이 템 을 잃 어 버 리 면 create () 를 다시 씁 니 다. 호출 코드 를 간소화 하고 잃 어 버 려 도 되 돌아 갑 니 다.기본 cache 크기 는 측정 한 item 의 수량 입 니 다. size of 를 다시 써 서 서로 다른 item 의 크기 를 계산 합 니 다.
참조 링크:http://blog.csdn.net/linghu_java/article/details/8574102
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
데이터 지향 설계(Data Oriented Design)에서의 게임 개발에 대해서게임 개발을 할 때의 생각에는 데이터 지향 설계(Data Oriented Design)라는 것이 있습니다. 지난 수십 년 동안 CPU 성능이 1만배 이상인 반면 메모리 성능은 10배 미만밖에 되지 않았습니다. 또한 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.