SparseArray와 이점

aufcl4858·2025년 9월 21일
post-thumbnail

안드로이드 개발을 하다 보면 성능 최적화에 대한 고민이 끊이지 않는다. 특히 메모리 사용량과 관련된 이슈는 사용자 경험에 직접적인 영향을 미치기 때문에 더욱 신경이 쓰인다. 오늘은 안드로이드에서 제공하는 효율적인 자료구조 중 하나인 SparseArray에 대해 알아보고, 언제 어떻게 사용하면 좋을지 정리해보겠다.

SparseArray란 무엇인가?

SparseArray는 안드로이드에서 제공하는 자료구조로, HashMap<Integer, Object>의 메모리 효율적인 대안이다. 이름에서 알 수 있듯이 'Sparse(희소한)' 배열 구조를 가지고 있으며, int 타입의 키를 사용하여 값을 저장하고 검색할 수 있다.

일반적으로 우리가 정수를 키로 사용하는 해시맵을 만들 때 HashMap<Integer, Object>를 사용하곤 하는데, 이때 매번 Integer 객체가 생성되면서 불필요한 메모리 오버헤드가 발생한다. SparseArray는 이런 문제를 해결하기 위해 만들어진 자료구조다.

실제 사용 예제

실무에서 어떻게 활용할 수 있는지 구체적인 예제를 살펴보자.

기본 사용법

// 기존 HashMap 방식
HashMap<Integer, String> hashMap = new HashMap<>();
hashMap.put(1, "Apple");
hashMap.put(5, "Banana");
hashMap.put(10, "Cherry");

// SparseArray 방식
SparseArray<String> sparseArray = new SparseArray<>();
sparseArray.put(1, "Apple");
sparseArray.put(5, "Banana");
sparseArray.put(10, "Cherry");

// 값 조회
String value = sparseArray.get(5); // "Banana"
String defaultValue = sparseArray.get(99, "Default"); // 없는 키는 기본값 반환

안드로이드에서의 실용적 활용

View 캐싱: findViewById 호출을 줄이기 위한 뷰 캐싱에 매우 유용하다.

SparseArray<View> viewCache = new SparseArray<>();
viewCache.put(R.id.textView, findViewById(R.id.textView));
viewCache.put(R.id.button, findViewById(R.id.button));

// 필요할 때 캐시에서 가져오기
TextView textView = (TextView) viewCache.get(R.id.textView);

사용자 데이터 매핑: 사용자 ID와 같은 정수 키를 사용하는 경우

SparseArray<User> userArray = new SparseArray<>();
userArray.put(1001, new User("김철수"));
userArray.put(1002, new User("이영희"));

User user = userArray.get(1001);

설정값 저장: 앱 설정과 같은 플래그 관리

SparseArray<Boolean> settingsArray = new SparseArray<>();
settingsArray.put(SETTING_NOTIFICATION, true);
settingsArray.put(SETTING_SOUND, false);

boolean isNotificationOn = settingsArray.get(SETTING_NOTIFICATION, false);

주요 메서드들

SparseArray는 다양한 유용한 메서드들을 제공한다.

SparseArray<String> array = new SparseArray<>();

// 데이터 추가
array.put(10, "Ten");
array.append(20, "Twenty"); // 키가 마지막보다 클 때 최적화된 추가

// 데이터 조회
String value = array.get(10);
String valueWithDefault = array.get(30, "Default");

// 데이터 삭제
array.delete(10);
array.remove(20);

// 크기 및 인덱스 기반 접근
int size = array.size();
int key = array.keyAt(0);
String val = array.valueAt(0);

// 순회
for (int i = 0; i < array.size(); i++) {
    int k = array.keyAt(i);
    String v = array.valueAt(i);
    Log.d("SparseArray", k + " : " + v);
}

SparseArray의 주요 이점

메모리 효율성

가장 큰 장점은 메모리 사용량의 대폭적인 감소다. HashMap<Integer, Object>를 사용할 때 발생하는 Integer 객체의 오토박싱/언박싱 오버헤드를 완전히 제거한다. 각 Integer 객체는 약 16바이트의 메모리를 사용하는데, SparseArray는 원시 int 타입을 사용하여 메모리 사용량을 최대 50%까지 절약할 수 있다.

성능 향상

작은 크기의 데이터셋에서는 HashMap보다 빠른 성능을 보인다. 일반적으로 100개 이하의 요소를 다룰 때 이진 탐색을 사용하여 효율적인 검색을 제공한다. 또한 연속된 메모리 공간에 데이터를 저장하여 CPU 캐시 지역성이 좋아 캐시 효율성이 높다.

가비지 컬렉션 부담 감소

불필요한 Integer 객체 생성이 줄어들어 가비지 컬렉션 빈도와 시간이 감소한다. 이는 특히 모바일 환경에서 배터리 효율성 향상으로 이어진다.

안드로이드 환경 최적화

안드로이드의 제한된 메모리 환경에 특화되어 설계되었다. 적은 메모리 사용과 빠른 처리로 전체적인 앱 성능 향상에 기여한다.

SparseArray의 한계

모든 도구가 그렇듯 SparseArray도 한계가 있다. 이를 명확히 이해하고 사용해야 한다.

키 타입 제한

가장 큰 제약은 int 키만 사용할 수 있다는 점이다. String, Long, 또는 다른 객체 타입을 키로 사용해야 한다면 SparseArray를 사용할 수 없다. 또한 음수 키를 사용할 때는 성능이 떨어질 수 있다.

크기 제한

대용량 데이터에는 적합하지 않다. 수백 개 이상의 요소를 다룰 때는 HashMap이 더 효율적일 수 있다. SparseArray는 이진 탐색 기반이므로 O(log n)의 시간 복잡도를 가지는 반면, HashMap은 평균적으로 O(1)의 시간 복잡도를 제공한다.

기능 제한

HashMap에 비해 제공하는 기능이 제한적이다. 멀티스레드 환경에서 동시성을 지원하지 않으므로 별도의 동기화가 필요하다. 또한 null 값과 삭제된 값을 구분하기 어려운 경우가 있다.

언제 사용해야 할까?

사용이 권장되는 경우

View ID나 리소스 ID 매핑: 안드로이드 리소스 ID는 정수이므로 SparseArray가 완벽하게 맞다.

작은 크기의 설정값 저장: 앱 설정이나 플래그와 같은 작은 규모의 데이터 관리에 적합하다.

메모리 최적화가 중요한 상황: 메모리 사용량이 중요한 모바일 앱에서 특히 유용하다.

빈번한 조회가 필요한 작은 캐시: 자주 접근하는 작은 규모의 캐시 구현에 효과적이다.

사용을 피해야 하는 경우

대용량 데이터 처리: 수천 개 이상의 데이터를 다룰 때는 HashMap을 사용하는 것이 좋다.

문자열이나 객체를 키로 사용: int가 아닌 다른 타입의 키가 필요한 경우에는 사용할 수 없다.

빈번한 삽입/삭제: 데이터의 삽입과 삭제가 매우 빈번한 경우에는 성능상 불리할 수 있다.

멀티스레드 환경: 동시성이 필요한 환경에서는 추가적인 동기화 작업이 필요하다.

관련 클래스들

안드로이드는 SparseArray 외에도 비슷한 목적의 다른 클래스들을 제공한다.

SparseBooleanArray: boolean 값을 저장하는 특화된 버전

SparseIntArray: int 값을 저장하는 특화된 버전

SparseLongArray: long 값을 저장하는 특화된 버전

LongSparseArray: long을 키로 사용하는 버전

이들은 각각 특정 타입에 최적화되어 있어 해당 타입을 다룰 때 더 나은 성능을 제공한다.

실무 팁

실제 프로젝트에서 SparseArray를 효과적으로 활용하기 위한 몇 가지 팁을 공유한다.

적절한 초기 크기 설정: 예상되는 요소 수를 알고 있다면 생성자에서 초기 크기를 지정하여 재할당 오버헤드를 줄일 수 있다.

append() 메서드 활용: 키가 오름차순으로 추가되는 경우 put() 대신 append()를 사용하면 더 효율적이다.

정기적인 성능 테스트: 데이터 크기가 변할 수 있는 경우 정기적으로 HashMap과 성능을 비교해보는 것이 좋다.

마무리

SparseArray는 안드로이드 개발에서 메모리 효율성을 높이는 유용한 도구다. 특히 정수 키를 사용하는 작은 규모의 데이터를 다룰 때 HashMap보다 훨씬 효율적이다.

하지만 모든 상황에 만능은 아니므로, 사용하기 전에 데이터의 크기, 접근 패턴, 키의 타입 등을 종합적으로 고려해야 한다. 적절한 상황에서 올바르게 사용한다면 앱의 메모리 사용량을 크게 개선하고 전체적인 성능 향상을 가져올 수 있을 것이다.

profile
데브누누

0개의 댓글