LruCache란?

면접 또는 코딩테스트에서 흔히 접할 수 있는 주제가 바로 LruCache다.
안드로이드에서는 LruCache가 어떻게 동작하고, 언제 그리고 어디서 사용되는지 한번 알아보도록 하자.

LruCache에서 Lru란 Least Recently Used(최근에 가장 적게 참조됨)의 약자다. 그러므로 즉, LruCache는 제한된 사이즈에서 참조(set or get)된지 가장 오래된 객체를 제거하는 데이터구조다. 그러므로 LruCache를 사용할때는 자주 참조되는 객체일 수록 빠르게 캐시를 통해 객체에 접근할 수 있다.

간단한 LruCache 예제

@Test
fun example1(){
    val cache = LruCache<String,Int>(5) // maxSize = 5
    
    cache.put("A",0) //[A]
    cache.put("B",0) //[A, B]
    cache.put("C",0) //[A, B, C]
    cache.put("D",0) //[A, B, C, D]
    cache.put("E",0) //[A, B, C, D, E] - A부터 E까지 캐싱 완료
    cache.put("F",0) //[B, C, D, E, F] - F를 캐싱하면, A는 제거됨
    cache.put("D",0) //[B, C, E, F, D] - D를 다시 캐싱하면 최근 참조된 상태로 변경
    cache.get("C") //[B, E, F, D, C] - C를 통해 캐시된 데이터 접근시 최근 참조된 상태로 변경
}

단일 Int형 매개변수를 갖는 생성자를 통해 LruCache 객체를 생성했다. 캐시의 사이즈는 5로 지정했다.

put(Key, Value) 메서드를 통해 캐싱을 시도 할 수 있다. 캐시에 있는 데이터를 참조할 때는 get(Key)메서드를 사용한다.

put 메서드를 통해 A부터 E까지 데이터를 넣으면 캐싱이 차곡차곡 되는 것을 확인할 수 있다. (지금 예제에서 캐시되는 값은 의미가 없으므로 0으로 통일했다).  그런 다음 F를 키로 갖는 6번째를 캐싱하려고 하면 캐시 사이즈를 초과하므로 최근에 가장 적게 참조된 A를 제거 하는 것을 확인할 수 있다. 이 후 캐시에 이미 포함된 키인 D로 캐싱을하면, D가 가장 최근에 참조된 키이므로 내부에서 데이터를 재배열 한다. 이후 get 메서드를 통해 키가 C인 값을 얻고자 하면 C가 가장 최근에 참조된 키이므로 다시 내부에서 데이터를 재배열하게 된다. 

캐시의 사이즈

앞의 예제에서는 지정된 캐시 사이즈내에서 데이터가 캐시되는 것을 확인했다. 이때 하나의 데이터가 캐시될 때 캐시 사이즈가 1(기본값)이기 때문에 자료구조에 총 5개의 데이터가 캐시되는 것을 확인 할 수 있었다. 캐시되는 사이즈를 재정의 하여 제한된 사이즈내에서 캐싱하는 것을 구현할 수 있다. 다음 나올 예제에서는 제한된 사이즈내에서 Bitmap 객체를 캐싱하는 것을 확인할 수 있다.

int cacheSize = 4 * 1024 * 1024; // 4MB
LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
    protected int sizeOf(String key, Bitmap value) {
        return value.getByteCount();
    }
}

캐시 사이즈를 4MB로 지정했다면 1MB의 Bitmap의 경우 4개 캐싱할 수 있고, 2MB의 Bitmap의 경우 2개를 캐싱할 수 있을 것이다. 또한 1MB짜리 2개, 2MB짜리 1개를 캐싱할 수도 있다. 비트맵이 100kb 라면 아마 40개의 Bitmap객체를 캐시할 수도 있다. (4*1024*1024 / (100*1024) = 40.96)

LruCache 실사용 예

위에서 언급했듯이 아무래도 LruCache를 사용하는 대표적인 예가 Bitmap캐싱이다.  RecyclerView와 같은 View에서 대량의 이미지를 한번에 로드하고 스크롤하여 재사용되는 경우 LruCache의 사용은 퍼포먼스 개선에 많은 도움이 된다. 많은 Bitmap을 메모리에 캐시하는 것은 부담될 수 있으므로 DiskLruCache와 같은 디스크 캐싱을 같이 사용하면 좀 더 메모리 부담은 줄일 수 있다. 실제로 Bitmap캐싱을 최적화하여 제공하고 있는 라이브러리가 Glide 같은 라이브러리다.

마무리하며

Bitmap 캐싱에 있어서 대부분의 경우는 Glide라이브러리를 사용하는 것을 추천한다. 하지만 그 외의 경우에 최근 사용한 데이터에 있어서 캐싱이 필요한 경우 LruCache사용을 고려할 수 있겠다. 취업 및 이직을 고려하고 있다면, 인터뷰 및 코딩 테스트 문제로 종종 나오는 내용이니 직접 LruCache 자료구조를 구현해보도록 하자.

Buy me a coffeeBuy me a coffee
카테고리: Android

0개의 댓글

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.