ArrayMap, SparseArray, LruCache에 대해서 알아보기
ArrayMap, SparseArray, LruCache In android.util
ArrayMap, SparseArray, LruCache란
기본 자료 구조보다 더 메모리 효율적으로 구현한 자료 구조로, android.util 패키지에 포함되어 있습니다.
ArrayMap
HashMap
을 개선한 버전입니다.HashMap
보다 좀 더 메모리 효율적입니다.
HashMap
ArrayMap
특징
- 구조
HashMap
- 배열 1개를 사용합니다.
- 키와 값을 저장하는 배열
- 키에 대해 Hash값을 구함 -> Hash값을 배열의 Index로 사용 -> 해당 Index에 값을 가져온다.
ArrayMap
- 배열 2개를 사용합니다.
- 키와 Hash값을 저장하는 배열, 키와 값의 쌍을 저장하는 배열
- 키에 대해 Hash값을 구함 -> Hash값으로 Key Index를 구함 -> 키와 값 쌍 배열에서 Key Index에 해당하는 값을 가져온다.
- 키 값 배열 크기 관리
- 데이터가 추가(제거)되면 배열을 사용되는 만큼 확장(축소)합니다.’
장점
- 낭비되는 메모리가 없습니다.
HashMap
- Map이 비어있더라도 기본적인 크기만큼 메모리가 할당되어 메모리가 낭비됩니다.
ArrayMap
- Map이 비어있으면, 아무것도 가지고 있지 않아 메모리가 할당되어 있지 않아 낭비되는 부분이 없습니다.
- 데이터 처리 시 메모리 효율직입니다.
- 키를 가지고 값을 찾을때
HashMap
은 Iterator를 통해서 값을 찾지만,ArrayMap
은 배열의 Index로 값을 찾기 때문에 메모리를 좀더 효율적으로 사용하게 됩니다.
- 키를 가지고 값을 찾을때
단점
- 데이터 조회 성능이
HashMap
보다 떨어집니다.ArrayMap
은 대량의 데이터를 처리하기에는 적합하지 않습니다.- Hash계산으로 바로 값을 가져올 수 있는
HashMap
와 달리ArrayMap
은 Hash계산 후 키와 값
- 스레드 동기화에 취약합니다.
- 인스턴스에 대해 동기화가 필요 없는 단일 스레드 환경에서 사용하기 적합합니다.
예제 코드
val arrayMap = ArrayMap<Long, String>()
arrayMap.put(1, "Dave") // id가 1인 Dave를 저장
val value = arrayMap.get("Name") // get name by id 1
SparseArray
기본
HashMap
보다 더 메모리 효율적인 Map구조를 제공합니다.ArrayMap
과 매우 유사합니다.
특징
- 구조
- Hashing없이 Primitive Int type인 키를 이진 검색으로 찾고, 값을 관리합니다.
장점
- 메모리 효율적입니다.
- AutoBoxing이 없습니다.
- 일반적으로
Map
은 키를 기본(Prmitive) Type(int)이 아닌 Wrapper Type(Integer)을 사용하기 때문에 추가적인 메모리 할당을 하고, 메모리 사용량이 늘어납니다. (Integer : 16 bytes, int : 4 bytes) - 그러나
SparseArray
는 Primitive Type(int)을 사용하기 때문에 추가적인 메모리 할당이 없기 때문에 메모리 사용량이 더 적습니다.
- 일반적으로
- AutoBoxing이 없습니다.
단점
- 데이터 조회 성능이
HashMap
보다 떨어집니다.SparseArray
는 대량의 데이터를 처리하기에는 적합하지 않습니다.- Hash계산으로 바로 값을 가져올 수 있는
HashMap
와 달리SparseArray
는 이진 검색으로 값을 찾기 때문에 처리 시간이 조금더 소요됩니다.
val sparseArray = SparseArray<String>()
sparseArray.put(1, "Dave") // id가 1인 Dave를 저장
val value = sparseArray.get(1) // get name by id 1
ArrayMap, SparseArray를 사용하기에 적합한 경우
- 처리할 데이터의 개수가 1,000개 미만
- Map의 값에 Map이 사용되는 경우
HashMap, ArrayMap, SparseArray 성능 비교
메모리 사용량 비교(낮을수록 우위)
SparseArray -> ArrayMap, HashMap(ArrayMap, HashMap은 비슷한 메모리 사용량을 보입니다.)
데이터 조회 성능 비교(낮을수록 우위)
SparseArray -> HashMap -> ArrayMap 처리해야할 데이터의 개수가 5,000개 이상이 되면서부터 격차가 크게 벌어집니다.
데이터 삽입 처리 시간 비교(낮을수록 우위)
SparseArray -> HashMap -> ArrayMap 처리해야할 데이터의 개수가 5,000개 이상이 되면서부터 격차가 크게 벌어집니다.
LruCache(Least Recently Used Cache)
Queue
를 기반으로, 데이터 사용빈도에 따라 데이터가 삭제 및 관리되는Caching
자료구조 입니다.
특징
- 구조
- 내부적으로
LinkedListHashMap
으로 구현되어 있으며Queue
를 기반으로 동작합니다. - Cache크기를 개발자가 정할 수 있습니다.
- 내부적으로
- 동작
- 데이터를 삽입할 때
- Queue의 맨 앞에 데이터를 삽입합니다.
- Cache크기가 가득 차있으면, 가장 오래된 데이터를 삭제하고 새로운 데이터를 삽입합니다.
- Cache크기가 가득 차있지 않으면, 새로운 데이터를 삽입합니다.
- 데이터를 조회할 때
- 데이터가 존재하면, 해당 데이터를 반환하고, Queue의 맨 앞으로 이동시킵니다.
- 데이터가 존재하지 않으면,
null
을 반환합니다.
- 데이터를 삽입할 때
Android 개발 시 주로 쓰이는 Glide 라이브러리가 기본적으로 사진 캐싱을 처리할 때 LruCache
를 사용합니다.
잘 안쓰이는 데이터는 자동으로 제거되기 때문에 불필요한 메모리 할당을 막을 수 있어, 상당히 효율적인 자료구조라고 생각됩니다.
val nameCache = LruCache<Long, String>(10) // id to name
nameCache.put(1, "Dave") // id가 1인 Dave를 저장
val name = lruCache.get(1) // get name by id 1