- Android 앱의 성능을 분석하고 최적화할 수 있도록 도와주는 도구입니다. CPU, 메모리, 네트워크, 전력 사용량 등 다양한 리소스 사용 현황을 실시간으로 시각화하여 보여주기 때문에, 앱의 병목 현상이나 리소스 누수 등을 진단하고 수정하는 데 매우 유용합니다. - Andriod Studio 내에서 Profiler 탭 내에서 확인할 수 있고, 연결된 디바이스에 따라서 디버깅이 가능합니다.
- Android 시스템 전체의 이벤트 흐름을 기록해 보여줍니다. - CPU 스레드 동작, 프레임 렌더링, 입력 이벤트, GPU 활동 등 시스템 레벨 분석 가능. - 렌더링 지연, ANR 원인 파악에 유용.
Analyze Memory Usage
Heap Dump
메모리 누수 분석
- 앱이 사용 중인 객체들의 메모리 상태를 스냅샷으로 캡처. - 어떤 클래스/객체가 얼마나 메모리를 차지하고 있는지 확인 가능. - 메모리 누수 탐지에 필수적.
Find CPU Hotspots
Callstack Sample
CPU 병목 탐색
- 주기적으로 스레드의 호출 스택을 샘플링해 CPU 사용이 높은 코드 파악. - 앱 성능에 큰 영향을 주지 않으면서 병목 지점 탐색. - lightweight profiling.
Track Memory Consumption
Java/Kotlin Allocations
메모리 누수 분석
- Java/Kotlin 객체 할당 정보를 기록. - 어떤 시점에 어떤 객체가 생성되었는지 추적. - 메모리 증가 원인 추적에 효과적.
Find CPU Hotspots
Java/Kotlin Method Recording
CPU 병목 탐색
- Java/Kotlin 함수 호출 시각화. - 각 메서드의 호출 횟수 및 실행 시간 정확하게 기록. - Callstack보다 세밀하지만, 성능 오버헤드 있음.
Track Memory Consumption
Native Allocations
네이티브 메모리 분석
- C/C++ 등 네이티브 코드에서의 메모리 할당 추적. - JNI 연동된 앱에서 메모리 누수나 과다 사용 진단에 유용.
View Live Telemetry
-
실시간 모니터링
- Profiler 탭에서 앱의 CPU, Memory, Network, Energy 사용 현황을 실시간 그래프로 시각화. - 빠르게 이상 징후를 파악하고 필요한 프로파일링 도구로 전환할 수 있는 대시보드 역할.
2) View Live Telemetry
💡View Live Telemetry
- Profiler 탭에서 앱의 CPU, Memory, Network, Energy 사용 현황을 실시간 그래프로 시각화하여 모니터링할 수 있습니다. - 빠르게 이상 징후를 파악하고 필요한 프로파일링 도구로 전환할 수 있는 대시보드 역할을 수행합니다.
1. View Live Telemetry 실행
💡 View Live Telemetry 실행
- Android Studio를 실행하고, Profiler 탭을 선택합니다. 그리고 연결된 앱을 선택 > View Live Telemetry > Start anyway를 선택합니다.
2. View Live Telemetry 실행 내용 확인
💡View Live Telemetry 실행 내용 확인
- 아래와 같이 수행시간 별 각각의 메모리를 측정해 줍니다.
분류
변화 가능성
메모리 설명
사용처
Java
자주 변함: 동적 객체 생성에 따라 변화 큼
- Java/Kotlin 코드에서 생성된 객체들이 할당되는 힙(Heap) 메모리 영역입니다.
- 일반적으로 앱의 new 연산자나 컬렉션 객체(List, Map 등) 등에서 할당된 인스턴스가 포함됩니다.
Native
중간~많이 변함: Bitmap 등에서 증가할 수 있음
- 앱 내부에서 C/C++ 또는 JNI를 통해 할당된 메모리입니다.
- 예: OpenCV, TensorFlow, MediaCodec, Bitmap 등 네이티브 라이브러리가 사용하는 메모리. - GC 대상이 아니므로 직접 해제해줘야 합니다.
Graphics
중간 : 뷰 추가/애니메이션 시 증가
- GPU와 관련된 메모리 리소스를 나타냅니다.
- 주로 OpenGL, Vulkan, Canvas, SurfaceView, ImageView 등에 의해 사용됩니다.
Stack
거의 고정 : 스레드 수 만큼 증가함
- 각 스레드의 콜 스택 메모리입니다.
- 스레드 생성 시 할당되는 메모리로, 지역 변수와 함수 호출 기록이 저장됩니다.
Code
거의 고정 : 앱 실행 후 안정됨
- 앱이 실행 중인 DEX 코드, 라이브러리, JNI 모듈, JIT 컴파일 결과 등이 저장되는 영역입니다.
- 일반적으로 앱 실행 중에는 크게 변하지 않으며, 초기 앱 로딩 이후 안정적인 값을 유지합니다.
Others
상황에 따라 다름 - 명확한 기준이 없음
- 위의 카테고리에 명확히 속하지 않는 기타 메모리
- 예: OS 내부 구조, 시스템 캐시, profiler 자체가 사용하는 메모리 등.
💡 View Live Telemetry를 통해서 의심해 볼 사항
상황
확인해 볼 상황(추론)
Java 영역이 계속 증가한다
- GC 이후에도 감소하지 않으면 메모리 누수 가능성 - 리스너, 콜백, Context 참조가 해제되지 않았을 수 있음 - Activity 또는 View가 참조된 상태로 남아 있음
Native 영역이 계속 증가한다
- Bitmap, MediaPlayer, OpenCV, TensorFlow 등에서 명시적 해제 누락 가능성 - C/C++에서 malloc() 해제 누락- ImageView에서 recycle() 안 함
Graphics 영역이 증가한다
- 뷰 재사용 없이 계속 추가하거나, 애니메이션/이펙트 무한 생성
- 프래그먼트 재생성 시 이전 뷰들이 해제되지 않음 - OpenGL 텍스처 누적 가능성
Stack 영역이 증가한다
- 스레드가 과도하게 생성되어 종료되지 않음 - 무한 루프나 ThreadPoolExecutor 잘못된 사용
Code 영역이 갑자기 증가한다
- JIT 컴파일, 네이티브 코드 로드(JNI) - 대용량 DEX, 외부 라이브러리 다수 포함 - 일반적으로는 안정되므로 급격한 증가는 드뭄
Others 영역이 크게 증가한다
- 시스템 버퍼, Binder, OS 내부 캐시 누적 - Profiler 자체가 리소스를 많이 사용 중일 수도 있음- 정확한 원인 파악이 어려워 전체 메모리 맥락에서 해석 필요
전체 메모리가 1GB 이상 고정된다
- OOM 가능성 높음, 메모리 해제 누락이 복합적으로 작용 중일 수 있음 - 프로파일링으로 Heap Dump 또는 Allocation Tracking으로 분석 필요
GC가 자주 발생하고 앱이 느려진다
- 많은 객체가 자주 생성되고 있음 (new 남발) - 리스트/어댑터 등에서 재사용 없이 뷰 무한 생성- 컬렉션에 객체 쌓이는데 clear() 안 함
3) View Live Telemetry 활용 사례 : 앱 내 메모리 개선 및 OOM(Out of Memory) 해결
1. 문제점 확인
💡 문제점 확인 - 아래와 같이 앱 내에서 메모리를 실시간으로 측정하였을 때, 활용하였습니다 - 주요한 사항은 앱을 실행하다가 ‘크러시 에러’가 발생하여서 앱이 종료되는 증상이 빈번히 발생하였습니다. Google Firebase Analytics나 Sentry 모니터링 툴에서 명확히 문제는 나오지 않았고, OOM으로 종료가 되었다는 것을 확인하였습니다. - 그렇기에 메모리 측정을 위해서 아래의 Android의 Profiler의 View Live Telemetry를 이용하여서 측정을 수행하기로 결정하였습니다.
[ 더 알아보기 ] 💡OOM(Out of Memory)
- 프로세스가 시스템으로부터 더 이상 메모리를 할당받을 수 없을 때 발생하는 오류, 즉, 할당 요청한 메모리 공간이 시스템 메모리를 초과했을 때 발생합니다.
💡 크러시 에러
- 앱이 예외 상황을 처리하지 못해 강제로 꺼지는 현상예: 앱이 갑자기 꺼짐, 화면이 멈춘 뒤 튕김
1.1. 시작 메모리 확인
💡 시작 메모리 확인
- 아래와 같은 상황에서 사용하였습니다. 앱을 실행하였을 때, 아래와 같이 492MB로 시작을 하였습니다.
1.2. OOM 발생
💡 OOM 발생
- 그러나 아래와 같이 앱의 코어 기능을 수행하면 아래와 같이 1시간이 지났을 때, 2.8GB가 증가가 됨을 확인하였습니다. - 아래의 주요 요소를 보면 Graphics 메모리의 값은 61MB → 1.4GB로 올라간 상황이었고 Native 메모리도 189MB → 939MB로 올라간 상황이었습니다.
1.3. 문제점 파악 -1: Native 메모리 증가 이슈
💡 문제점 파악 -1 :Native 메모리 증가 이슈
- 해당 경우를 확인해 보았을 때, 두 가지를 의심해 볼 수 있었습니다.
- 첫 번째로 Native 메모리가 오르는 경우는 Bitmap, MediaPlayer, OpenCV, TensorFlow 등에서 명시적 해제 누락 가능성을 의심해 볼 수 있습니다. - 해당 앱에서도 Tensorflow를 통한 연산을 수행했었고, GC가 직접 처리해 주는 것이 아니라 아래의 공식 사이트를 보면 실제로 사용한 메모리는 자동으로 처리되는 게 아니라 명시적으로 처리해야 한다고 합니다. - 해당 메모리 관리를 수행하지 않아서 메모리가 급격하게 증가하는 문제였습니다.
분류
변화 가능성
메모리 설명
사용처
Native
중간~많이 변함: Bitmap 등에서 증가할 수 있음
- 앱 내부에서 C/C++ 또는 JNI를 통해 할당된 메모리입니다.
- 예: OpenCV, TensorFlow, MediaCodec, Bitmap 등 네이티브 라이브러리가 사용하는 메모리. - GC 대상이 아니므로 직접 해제해줘야 합니다.
Graphics
중간 : 뷰 추가/애니메이션 시 증가
- GPU와 관련된 메모리 리소스를 나타냅니다.
- 주로 OpenGL, Vulkan, Canvas, SurfaceView, ImageView 등에 의해 사용됩니다.
1.4. 문제점 파악 -2: Graphics 메모리 증가 이슈
💡문제점 파악 -2: Graphics 메모리 증가 이슈
- 두 번째로 Native 메모리가 오르는 경우는 GPU와 관련된 메모리 리소스가 제대로 정리가 되지 않고 누적이 됨을 확인하였습니다.
- 해당 역시도 @tensorflow/tfjs-react-native 라이브러리의 expo-gl을 이용하고, 백엔드를 rn-webgl을 사용하였기에 그래픽 메모리를 사용함에 따라 증가함을 확인하였습니다. - 역시 위에와 같이 webgl을 이용하면서 해당 메모리 관리를 수행하지 않아서 메모리가 급격하게 증가하는 문제였습니다.