버미

[안드로이드] ANR 본문

안드로이드

[안드로이드] ANR

Bum_2 2025. 7. 22. 18:49

안드로이드 디버깅을 하다보면 ANR을 마주친다. ANR이 무엇인지 알아보자.


ANR

Application Not Responding의 약자이다. 어플리케이션이 응답하지 않을 때, 안드로이드 시스템에서 보여주는 에러다. 보통 메인 스레드(UI 스레드)가 5초 이상 동작하지 않을 때 접했을 것이다.

 


ANR이 발생하는 경우

ANR은 다양한 방법으로 발생한다. 공식 문서에 나와있는 두 가지 이유 이외에도 많은 경우에 ANR이 발생한다.

 

  • 터치를 통한 사용자 입력이 5초 내에 처리되지 않았을 때
  • 브로드캐스트가 10초 내에 처리되지 않았을 때
  • Activity 런치/전환이 10초 이상 걸리는 경우 (무거운 초기화, 동기 I/O, 큰 이미지 디코딩)
  • ContentProvider 관련 10초 이상 미응답 (앱 시작 시 Provider publish가 오래 걸리거나 Provider가 메인 스레드에서 오래 블록 되는 경우)
  • 느린 BInder/IPC를 메인 스레드에서 대기 ( 시스템이나 다른 프로세스에 동기 호출을 던지고 메인 스레드가 응답을 오래 기다리는 경우)

Figure 1.  How to debug an input dispatch ANR.

 

안드로이드 Developer에도 나와있듯이, 기술적 이유로서 ANR은 크게 4가지 이유 때문에 발생한다.

 

  1. Inactionable ANR
    • nativePollOnce(NDK 함수)나 "No stack frames"(몇 가지 이유에 의해 스택에 쌓인게 없어, 현재 스레드가 무엇을하고 있는지 알 수 없음)처럼, 시스템 내부에서 멈춘 것으로 보이지만 개발자가 코드 차원에서 대응할 수 없는 경우.
  2. Deadlock
    • 메인 스레드가 다른 스레드와 락을 서로 기다리며 교착상태에 빠진 경우.
    • 예: main thread ↔ worker thread가 서로 자원을 잡고 기다리는 상황.
  3. Lock contention
    • 메인 스레드가 락을 얻기 위해 대기 중인데, 락을 가진 holder thread가 너무 오래 점유하고 있어서 발생.
    • Deadlock까지는 아니고, 단순히 락을 오래 잡아서 Main thread가 묶여 있는 경우임.
  4. 그 외의 경우 
    • GPU hang → GPU 자체가 멈춘 경우
    • Slow binder call → 메인 스레드가 Binder IPC 호출을 했는데 응답이 느린 경우
    • Blocked by other component → 메인 스레드가 다른 컴포넌트 작업 중이라 막혀 있는 경우
    • Generic slow/blocking code → 단순히 메인 스레드에서 오래 걸리는 코드 실행 (ex. 파일 I/O, 네트워크, 무거운 계산 등)

ANR을 피하는 방법

공식 문서에서 언급한 내용을 정리하면 다음과 같다.

  • 메인 스레드를 절대 막지 말 것
    긴 작업·블로킹 작업은 워커 스레드로 분리.
  • 락 경합 최소화
    메인 스레드와 다른 스레드 사이의 동기화·락 사용을 줄이기.
  • 메인 스레드에서 비-UI 작업 최소화
    특히 onCreate(), onResume() 같은 액티비티 생명주기 콜백은 가볍게.
  • 앱 시작(Cold Start) 빠르게
    Dagger 초기화 등 느린/블로킹 코드를 스타트업 경로에서 빼기.
  • 스레드 풀 공유 주의
    오래 블록될 작업시간 민감 작업(예: 브로드캐스트 처리)을 같은 풀/스레드에 섞지 말기.
  • 브로드캐스트/서비스 관련
    • BroadcastReceiver는 가능하면 비-메인 스레드로 처리(Context.registerReceiver 활용).
    • goAsync() 사용 시 PendingResult.finish()를 타임아웃 전에 빠르게 호출.

 

 

Reference

 

- Keep your app responsive

 

- Diagnose and fix ANRs