
최근에 LinkedList 사용 예제를 공부하던 중, LRU 캐시(Least Recently Used Cache)라는 개념을 알게 되었습니다.
LRU 캐시는 오래 사용되지 않은 데이터를 자동으로 삭제하는 캐싱 기법으로, 메모리 관리에서 중요한 역할을 합니다.
그런데, LRU 캐시는 단순한 LinkedList가 아니라, "해시 테이블과 이중 연결 리스트가 결합된 LinkedHashMap을 활용하여 구현되는 경우가 많다"는 것을 알게 되었습니다.
또한, 안드로이드에서 Glide 라이브러리도 LinkedHashMap을 기반으로 한 LRU 캐시를 활용하여 Bitmap(이미지) 데이터를 캐싱하고 있었습니다.
따라서 이번 글에서는 LRU 캐시의 개념과 함께, Glide가 이를 활용하여 어떻게 성능을 최적화하는지 정리해 두겠습니다.
1. LRU 캐시란?
LRU (Least Recently Used) 캐시는 가장 오랫동안 사용되지 않은 데이터를 삭제하는 캐싱 기법입니다.
즉, 캐시 크기가 정해져 있기 때문에, 새로운 데이터가 들어오면 가장 오래 사용되지 않은 데이터를 제거하고 새로운 데이터를 저장하는 방식입니다.
📌 LRU 캐시의 핵심 원리
- 새로운 데이터가 추가되면, 가장 최근에 사용된 상태로 저장됩니다.
- 이미 존재하는 데이터를 다시 사용할 경우, 최근 사용한 데이터로 갱신됩니다.
- 캐시가 꽉 차면, 가장 오래 사용되지 않은 데이터를 삭제합니다.
즉, 자주 사용하는 데이터는 캐시에 남고, 오래 사용하지 않은 데이터는 자동으로 삭제되는 구조입니다.
2. LRU 캐시는 어떻게 동작할까? (LinkedHashMap 사용)
Java와 Kotlin에서는 LinkedHashMap을 활용하여 LRU 캐시를 구현할 수 있습니다.
LinkedHashMap은 이중 연결 리스트(Double Linked List)와 해시맵(HashMap)을 결합한 자료구조로,
데이터 삽입 순서 또는 사용 순서를 유지할 수 있는 특징을 가집니다.
특히, LRU 캐시는 Key-Value 저장이 가능하고, 최근 사용된 순서를 유지할 수 있다는 장점으로 인해 LinkedHashMap을 활용하는 것이 일반적입니다.
단순한 LinkedList만으로 LRU 캐시를 구현할 경우 검색 성능이 떨어지지만,
LinkedHashMap을 사용하면 해시 테이블을 활용해 빠른 검색(O(1))과 순서 유지가 동시에 가능합니다.
📌 LRU 캐시를 LinkedHashMap으로 구현하는 예제
class LruCache<K, V>(private val maxSize: Int) : LinkedHashMap<K, V>(maxSize, 0.75f, true) {
override fun removeEldestEntry(eldest: MutableMap.MutableEntry<K, V>?): Boolean {
return size > maxSize // 캐시가 꽉 차면 가장 오래된 데이터 삭제
}
}
- LinkedHashMap을 사용하면, 데이터가 자동으로 정렬되면서 가장 최근에 사용된 항목이 앞으로 이동합니다.
- 이전 데이터는 뒤로 밀려나고, 캐시 크기를 초과하면 가장 오래된 데이터가 삭제됩니다.
이러한 방식으로 오래된 데이터를 자동으로 관리하면서 빠르게 접근할 수 있습니다.
3. Glide에서 LRU 캐시는 어떻게 활용될까?
Glide는 내부적으로 LRU 메모리 캐시(LruResourceCache)와 LRU 디스크 캐시(DiskLruCache)를 활용하여
이미지를 빠르게 로드하고, 불필요한 메모리 사용을 방지합니다.
📌 Glide의 3단계 캐싱 구조
- 메모리 캐시 (LRU Memory Cache)
- LruCache를 사용하여 자주 사용되는 이미지를 메모리에 저장합니다.
- 메모리가 부족하면, 가장 오래 사용되지 않은 이미지부터 삭제됩니다.
- Glide의 LruResourceCache에서 관리됩니다.
- 디스크 캐시 (LRU Disk Cache)
- DiskLruCache를 사용하여 이미지를 내부 저장소(캐시 폴더)에 저장합니다.
- 앱이 종료되거나 화면을 벗어나도 다시 다운로드할 필요 없이 디스크에서 불러올 수 있습니다.
- 네트워크 캐시 (Remote Fetch)
- 메모리/디스크 캐시에 없으면 네트워크에서 이미지를 다시 다운로드합니다.
- 다운로드된 이미지는 다시 LRU 캐시에 저장되어 재사용 가능합니다.
4. Glide의 메모리 캐시 LRU 적용 예제
Glide는 내부적으로 LruResourceCache를 사용하여 Bitmap을 메모리에 캐싱합니다.
사용자가 이미지를 요청하면, Glide는 캐시를 먼저 확인하고, 없으면 디스크나 네트워크에서 불러오는 방식을 사용합니다.
📌 Glide의 LRU 캐싱 적용 예제
val requestOptions = RequestOptions()
.skipMemoryCache(false) // 메모리 캐시 사용 (LRU 적용)
.diskCacheStrategy(DiskCacheStrategy.ALL) // 디스크 캐시도 함께 사용
Glide.with(context)
.load("https://example.com/image.jpg")
.apply(requestOptions)
.into(imageView)
- 1) Glide는 먼저 메모리 캐시(LRU)를 확인합니다.
- 2) 캐시에 없으면 디스크 캐시를 확인합니다.
- 3) 디스크에도 없으면 네트워크에서 다운로드 후 LRU 캐시에 저장합니다.
5. LRU 캐시에서 "이미지를 삭제한다"는 의미
Glide의 LRU 캐시에서 "이미지를 삭제한다"는 의미는 단순히 메모리에서 제거된다는 뜻이며, 앱에서 이미지가 보이지 않게 된다는 의미는 아닙니다.
- 캐시가 꽉 차면, 가장 오래 사용되지 않은 이미지부터 삭제됩니다.
- 하지만 삭제된 이미지는 다시 요청하면 네트워크 또는 디스크에서 불러올 수 있습니다.
- 즉, 삭제되었다고 해서 앱 화면에서 이미지가 사라지는 것은 아닙니다.
결론적으로, 캐시에서 제거되었을 뿐, 다시 요청하면 Glide가 자동으로 불러와서 화면에 표시됩니다.
6. 정리: Glide의 LRU 캐싱과 LinkedHashMap 활용
항목 | 설명 |
LRU 캐시란? | 가장 오래 사용되지 않은 데이터를 제거하는 캐싱 방식 |
왜 필요할까? | Android에서 Bitmap을 무작정 저장하면 OOM(메모리 부족) 오류가 발생할 수 있음 |
어떻게 동작할까? | LinkedHashMap을 이용하여 최근 사용한 데이터를 앞으로 정렬하고, 캐시가 꽉 차면 오래된 데이터를 삭제 |
Glide에서 어떻게 적용될까? | LruResourceCache(메모리 캐시)와 DiskLruCache(디스크 캐시)를 활용하여 최적의 성능 유지 |
삭제된 이미지는 어떻게 될까? | 캐시에서 제거되었을 뿐, 다시 요청하면 디스크 또는 네트워크에서 불러와서 다시 표시됨 |
결론: Glide는 LRU 캐시를 활용해 메모리를 최적화하고 빠르게 이미지를 로드한다
Glide는 LruResourceCache(메모리)와 DiskLruCache(디스크)로 LRU 캐시를 구현하여 불필요한 메모리 사용을 방지합니다.
캐시가 꽉 차면 가장 오래 사용되지 않은 이미지를 삭제하지만, 다시 요청하면 자동으로 불러와 표시됩니다.
이러한 최적화 덕분에 Glide는 빠르고 메모리 효율적인 이미지 로딩을 제공할 수 있습니다.
참고: https://charlezz.com/?p=44551
안드로이드에서 LruCache를 파헤치기 | 찰스의 안드로이드
LruCache란? 면접 또는 코딩테스트에서 흔히 접할 수 있는 주제가 바로 LruCache다. 안드로이드에서는 LruCache가 어떻게 동작하고, 언제 그리고 어디서 사용되는지 한번 알아보도록 하자. LruCache에서 Lr
charlezz.com
https://velog.io/@haero_kim/LRU-Cache-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0
LRU Cache 이해하기
상당히 유용하게 사용되는 LRU 캐싱 이해하기
velog.io