비트맵은 앱에서 가장 많은 메모리를 사용하는 객체인 경우가 많습니다. 디코딩 및 확장 작업은 프레임 렌더링의 중요한 경로에 있는 경우가 많습니다. 비트맵 메모리 사용량을 최적화하면 버벅거림, ANR, OOM 관련 프로세스 종료를 줄여 UI 응답성, 배터리 수명, 전반적인 안정성이 크게 개선됩니다.
높은 비트맵 메모리 사용량 식별
Android vitals는 Android 기기의 데이터를 집계하여 앱의 비트맵 메모리 사용량에 관한 측정항목을 제공합니다. 이러한 측정항목에는 패키지 및 프로세스별 기간 기반(예: 28일) 백분위수가 포함됩니다. 이 데이터는 다양한 기기 유형과 버전에서 메모리 효율성의 추세와 잠재적 회귀를 식별하는 데 도움이 됩니다.
Android vitals는 다음과 같은 프로세스 상태별로 분류된 앱의 비트맵 메모리 사용량을 공유합니다.
- 포그라운드: 앱의 프로세스가 표시됩니다. P99는 다른 프로세스 상태에 비해 포그라운드에서 훨씬 더 높을 것으로 예상되지만 개발자는 P99/P50 비율이 상당한지 (예: 3.5배 초과) 조사해야 합니다. 이는 비트맵 메모리 누수를 나타내는 경우가 많기 때문입니다. 일반적인 사용량 (P50)과 이상점 사용량 (P99) 간의 차이를 확인하여 이를 식별할 수 있습니다. 일반적인 애셋 블로트는 모든 백분위수에서 메모리를 균일하게 부풀리는 반면 메모리 누수는 시간이 지남에 따라 누적되어 꼬리 끝 데이터 (P99)를 크게 왜곡합니다. 앱이 다른 상태로 전환된 후 포그라운드 비트맵 할당이 불필요하게 지속되지 않도록 하세요.
- 사용자가 인식하는 서비스: 앱의 프로세스가 인식 가능한 상태로 실행되고 있습니다. 여기에는 포그라운드 서비스, 신속한 작업, 사용자 시작 데이터 전송 작업이 포함됩니다. 앱은 이러한 상태로 전환할 때 과도한 포그라운드 비트맵 할당을 유지해서는 안 됩니다. 이러한 서비스는 장기 실행 작업을 위해 설계되었으므로 대규모 애셋을 보유하면 전반적인 사용자 환경이 저하되고 LMK(Low Memory Killer Daemon)가 우선순위가 낮은 프로세스를 종료하여 메모리를 회수해야 합니다.
- 백그라운드: 앱이 백그라운드 서비스를 실행 중이거나 최근에 백그라운드로 전환되었지만 아직 캐시되지 않았습니다. 이 프로세스 상태는 포그라운드 또는 인식 가능한 프로세스보다 중요하지 않으므로 앱은 메모리 압력을 줄이기 위해 여기서 대규모 비트맵 애셋을 명시적으로 해제해야 합니다.
- 캐시됨: 앱이 캐시된 상태입니다. 이 상태는 LMK와 같은 시스템 메모리 압력에 매우 민감합니다. 앱은 OS에 의한 삭제를 방지하기 위해 이 상태에서 비트맵 메모리 사용량을 사전에 줄여야 합니다.
높은 비트맵 메모리 사용량의 기여자
사용되지 않은 가상 메모리도 계산에 포함될 수 있습니다. 예상치 못한 높은 비트맵 메모리 사용량이 표시되면 사용되지 않는 메모리를 할당하지 않는지 확인하세요.
리소스
Android 스튜디오에서 비트맵 분석
비트맵용 Android 스튜디오 프로파일링
메모리 프로파일러를 사용하여 메모리 할당을 실시간으로 검사하고, 힙 덤프를 캡처하고, 객체에서 메모리 누수를 분석합니다. 또한 힙 분석기를 사용하여 메모리 누수를 감지하고, 중복 비트맵 할당을 식별하고, 객체 보관을 시각화합니다.
LeakCanary를 사용한 자동 누수 감지
LeakCanary 라이브러리를 통합하여 앱에서 메모리 누수를 자동으로 감지합니다. LeakCanary는 자동 힙 분석을 제공하여 가비지 컬렉션되었어야 하지만 소멸된 활동 또는 프래그먼트에 의해 보관된 비트맵과 같이 메모리에 계속 보관되는 객체를 식별합니다.
비트맵 성능 문서
이러한 리소스는 다양한 Android 구성요소에서 효율적인 비트맵 처리를 위한 권장사항에 관한 포괄적인 안내를 제공합니다.
비트맵 메모리 사용량 최적화를 위한 개발자 체크리스트
비트맵 메모리 효율성을 최적화하려면 줄이기, 재사용, 재활용이라는 세 가지 핵심 원칙을 따르세요.
- 줄이기: 비트맵을 로드하거나 표시할 때 초기 메모리 사용량을 최소화합니다.
- 재사용: 중복 비트맵 할당을 방지하기 위해 캐싱 메커니즘을 구현합니다.
- 재활용: 활성 프로세스의 메모리 재할당을 허용하기 위해 리소스를 사전에 해제합니다.
다음 개발자 체크리스트는 비트맵 메모리 사용량을 최적화하는 데 도움이 될 수 있습니다.
| 핵심 원칙 | 영역 | 설명 |
|---|---|---|
| 줄이기 | 중복 비트맵 삭제 | 메모리 프로파일러를 사용하여 힙 덤프를 분석하여 중복 비트맵 할당을 감지합니다. 비트맵 메모리 관리 가이드를 참고하세요. |
| 이미지 로드 라이브러리 활용 | Glide 및 Coil과 같은 라이브러리를 사용하여 스레딩, 캐싱, 효율적인 디코딩을 자동화합니다. | |
| 다운샘플링 구현 | 이미지를 디코딩하여 전체 해상도 애셋을 로드하는 대신 타겟 UI 컨테이너 크기에 맞게 조정합니다. | |
| 불투명 이미지에 RGB_565 사용 | 투명도가 없는 이미지의 경우 ARGB_8888에서 16비트 구성으로 전환하여 메모리 사용량을 50% 줄입니다. |
|
| VectorDrawable 우선순위 지정 | 아이콘 및 기본 그래픽에 벡터를 사용하여 최소한의 메모리 오버헤드로 선명한 확장을 보장합니다. | |
| 서버 측 이미지 전송 최적화 | 기기 밀도 및 ImageView 크기에 맞게 이미지를 제공하도록 백엔드 API를 구성합니다. | |
| 투명한 여백 삭제 | 기본 제공 여백 대신 InsetDrawable 또는 레이아웃 패딩을 사용하여 '보이지 않는' 픽셀에 메모리를 할당하지 않습니다. 메모리 성능이 우수한 Android 앱 엔지니어링을 참고하세요. | |
| 재사용 | 최적의 캐시 크기 구성 | 기기 RAM 및 화면 해상도에 따라 메모리 및 디스크 캐시 한도를 맞춤설정합니다. 비트맵 캐싱을 참고하세요. |
| 재활용 | 백그라운드에서 리소스 삭제 | 를 구현하여 캐시를 지우고 시스템 메모리 압력 중에 프로세스 생존을 개선합니다.TRIM_MEMORY_BACKGROUND |
| UI가 숨겨질 때 애셋 해제 | 앱이 더 이상 사용자에게 표시되지 않을 때 TRIM_MEMORY_UI_HIDDEN을 사용하여 비트맵 캐시를 해제합니다. |
|
| 메모리 누수 모니터링 | LeakCanary 및 메모리 프로파일러를 사용하여 LifecycleOwner가 소멸된 후 보관된 비트맵을 찾습니다. 앱 메모리 관리를 참고하세요. |