tech

Android 비트맵 로딩 라이브러리에 대한 벤치마크 테스트

모바일 앱을 개발할 때 서버에서 비트맵 이미지를 받아 보여주는 기능을 구현해야 할 경우가 있습니다.

안드로이드에서는 BitmapFactory와 같은 저수준 API만을 제공하기 때문에 이를 위해 안정적으로 통신하고, 원하는 형식으로 가공하여 효율적인 자원 사용을 통해 노출하는 것은 상당히 번거롭고 복잡한 처리가 필요한 작업입니다. 다행히 이 문제들을 해결하기 위한 다양한 라이브러리가 공개되어 있습니다.

하이브 SDK가 사용했던 ‘Android Universal Image Loader(AUIL)’ / github 페이지 캡쳐

Hive SDK에서는 다양한 선택지 중에 ‘Android Universal Image Loader’(이하 ‘AUIL’)라는 라이브러리를 도입하여 사용하고 있었습니다. 2011년 11월 27일 개발자 Sergey Tarasevich에 의해 공개된 AUIL은 이미지 로딩 및 표시를 위한 강력하고 유연하며 높은 수준의 커스터마이징을 지원하는 것이 특징입니다. 하지만 2015년 11월 27일 더 이상의 유지 보수가 중단되었고 최신 버전의 Android에서 발생하는 이슈에 대응하기가 어려워졌습니다. 이에 따라 대안이 되는 라이브러리를 찾을 필요가 있었습니다. 

비트맵 로딩 라이브러리 

일반적으로 비트맵 로딩 라이브러리는 다음과 같은 기능으로 구성됩니다. 

[그림] 비트맵 로딩 라이브러리의 동작
  • Pre-processing: 미리 보기 이미지 노출 등 이미지 로드 및 노출 단계 전 수행해야 할 과정들을 처리합니다.
  • Memory Cache, Disk Cache: 재노출 상황에서 효율적인 자원 활용을 위해 캐시 처리를 수행합니다. 액티비티 생명주기, 뷰 재사용을 위한 뷰 홀더 패턴 등 안드로이드 시스템에 종속된 동작에 대한 고려와 메모리 초과가 발생하지 않는 범위 내에서 캐시 적중률을 높이기 위한 처리 등 복잡하고 다양한 처리가 필요합니다.
  • Network Download: 서버로부터 이미지 데이터를 받아옵니다. 실패, 재시도, 즉시 취소 등 불완전한 모바일 네트워크 환경에 알맞은 처리가 필요합니다.
  • Decode: 이미지 바이너리 데이터를 원하는 이미지 형식으로 변환합니다.
  • Post-processing: 이미지 노출 전 모양, 효과에 대한 옵션을 제공합니다.
Glide(글라이드) 로고

‘Glide’는 Bump Technologies에서 개발한 Android 비트맵 로딩 라이브러리입니다. 현재는 구글이 개발사를 인수하여 공식 문서에서 적극적인 사용을 권장할 만큼 표준으로 인정되고 있는 라이브러리입니다. 쉬운 사용법과 빠른 로딩 속도가 특징이며, 투명 배경을 위한 알파 값 및 GIF 형식을 지원합니다. 렌더링 하기 위한 이미지 뷰 크기를 미리 측정하여 비트맵 디코딩을 수행하므로 메모리 최적화도 뛰어납니다.

Coil
Coil(코일) 로고

‘Coil’은 Kotlin & Coroutines 기반의 비트맵 로딩 라이브러리입니다. OkHttp, Okio 및 AndroidX Lifecycles를 포함한 최신 라이브러리를 사용하고 있으며 확장 함수 등 Kotlin 언어 특성을 통해 간결한 사용법이 특징입니다. 추가 확장 라이브러리를 통해 GIF 형식을 지원하고 있습니다.

Fresco An image management library. | Fresco
Fresco(프레스코) 로고

‘Fresco’는 Meta 사에서 제공하는 라이브러리로, XML 레이아웃 작성 시에 별도의 뷰를 사용해야 하는 등 제약 사항이 많습니다. 따라서 이번 벤치마크 테스트에서는 ‘AUIL’, ‘Glide’, ‘Coil’ 3종의 라이브러리만을 대상으로 하였습니다. 

테스트 환경

벤치마크 테스트를 수행한 환경은 아래와 같습니다. 

  • Galaxy 10+ (Android 11)
  • Gradle / AGP 7.0.2
  • targetSdkVersion 31
  • Android Studio Chipmunk 2021.2.1 Beta 3 Profiler

Android Profiler를 이용해 비트맵 이미지의 로딩뿐만 아니라, 앱 실행 사이클 전체 자원 소모를 측정하였습니다. 단, CPU, 메모리 수치는 순간 최대 사용량을 기준으로 비교하였습니다. 

[그림] Android Profiler 예시

[그림] 테스트에 사용한 샘플 이미지

복수 이미지 노출 (40장)

메모리와 디스크 캐시가 비어 있는 상태에서 동시 요청에 대한 부하 테스트를 수행하여 네트워크 다운로드 전체 워크플로우를 측정하였습니다. 최초 노출 시, ‘Coil’이 ‘AUIL’ 대비 약 2배 빨랐으나 가장 많은 자원을 소모했습니다. 캐시 데이터를 사용하게 되는 재시도 테스트에서는 상대적으로 차이가 없었습니다. ‘Glide’는 속도와 자원 사용량 간의 균형을 고려해 상대적으로 우수한 것으로 보입니다. 

테스트 결과

큰 사이즈의 단일 이미지 노출 (4K)

큰 사이즈의 이미지를 디코딩 하는 데는 상당한 자원이 소요될 것으로 예상하여 별도의 케이스로 테스트를 하였습니다. 최초 노출 시, 작은 사이즈의 이미지 처리에서는 가장 빨랐던 ‘Coil’이 큰 사이즈 이미지 처리에는 가장 느린 결과를 보였습니다. 재시도 시에도 그 결과는 큰 차이가 없었습니다. 큰 사이즈의 이미지 디코딩은 ‘Glide’가 가장 빠르지만, 메모리 자원도 더 많이 사용하였습니다. 

테스트 결과

단일 이미지 중복 노출 (4K, 40장)

단일 이미지를 중복해서 노출할 때 디코딩을 중복해서 처리하는지를 확인하기 위한 테스트였습니다. ‘Coil’은 기본 할당 메모리 사이즈 초과로 인해 이미지를 노출하지 못하고, 에러 결과를 반환하였습니다. ‘AUIL’은 이미지를 노출하였지만 기대한 결과는 아니었습니다. ‘Glide’는 중복된 이미지를 노출할 때 다른 라이브러리에 비해 압도적인 성능을 보여주었습니다. ‘Glide’는 노출할 이미지 뷰 크기를 미리 측정하여 디코딩을 수행하고, 중복된 이미지에 대해 이전 디코딩 결과를 재사용하여 메모리를 효율적으로 사용하는 것을 확인하였습니다.

테스트 결과


GIF 이미지 노출

움직이는 GIF를 사용하면 앱 사용자에게 다양한 시각적 경험을 제공할 수 있습니다. 이를 위해 GIF 형식의 비트맵 이미지에 대한 테스트를 수행했습니다. ‘AUIL’은 GIF 형식을 지원하지 않으며, ‘Glide’와 ‘Coil’의 성능 차이는 크지 않았습니다.

테스트 결과

맺음말

본 테스트 이전에는 비트맵 이미지의 로딩에 관련한 기능을 직접 구현하는 것도 고려하고 있었습니다. 하지만 구현에 필요한 Android API의 경우 OS 종속성에 따라 별도의 분기 처리가 필요하며, 이를 모두 처리하는 데는 상당한 유지 보수 비용이 발생하게 됩니다. ‘Glide’는 약 40여 개의 OS 종속성 분기 처리를 하였습니다. 만약 커스텀이 필요한 경우 라이브러리별 파이프라인 커스텀 기능을 제공하고 있기 때문에 경우에 따라 별도 작업을 진행할 수 있습니다. 타사 사례 조사 시, 이미 이 같은 이유로 대부분 오픈소스 라이브러리를 사용하고 있었습니다.

따라서 기존 사용하던 ‘AUIL’ 유지 보수 중단에 따른 대응으로 직접 구현하는 대신 이번 테스트에서 가장 양호한 결과를 도출한 ‘Glide’를 도입하기로 결정하였습니다.

참고 자료 (클릭시 링크 이동)

하이브 플랫폼 웹사이트 바로가기 https://platform.withhive.com/

김진태

컴투스 CI의 미소처럼 항상 기분좋은 사용자 경험을 전달할 수 있는 개발자가 되도록 노력하겠습니다.


TOP