관리 메뉴

나만을 위한 블로그

[Manifest-Android] 13. 메모리 관리, 메모리 누수 처리 본문

스터디

[Manifest-Android] 13. 메모리 관리, 메모리 누수 처리

참깨빵위에참깨빵_ 2025. 6. 23. 20:27
728x90
반응형

안드로이드는 안 쓰는 메모리는 자동 회수하는 GC 메커니즘을 통해 메모리를 관리해서 활성된 앱, 서비스에 효율적으로 메모리가 할당되는 걸 보장한다.

C++ 같은 언어처럼 직접 메모리를 할당, 해제할 필요가 없다. 달빅 또는 ART 런타임은 메모리 사용량을 모니터링하고 안 쓰는 객체를 정리해서 과한 메모리 소비를 방지한다.

안드로이드는 low-memory killer를 써서 시스템 메모리가 부족할 때 백그라운드 프로세스를 종료해 포그라운드 앱의 원활한 작동을 우선시한다.

 

메모리 누수 막기

 

  • 생명주기 인식 컴포넌트 사용 : 뷰모델, Flow 같은 생명주기 인식 컴포넌트를 collectAsStateWithLifecycle 또는 LiveData와 같이 쓰면 해당 생명주기 종료 시 리소스가 적절하게 release된다. 이런 컴포넌트는 관련 생명주기가 더 이상 활성화되지 않거나, 특정 상태로 변경 시 자동 정리된다
  • 컨텍스트 참조를 유지하지 않기 : 정적 필드, 싱글톤 같이 생명이 긴 객체에서 액티비티 or 컨텍스트에 대한 참조를 유지하지 않는다. 가능하면 액티비티, 프래그먼트 생명주기에 연결되지 않는 ApplicationContext를 사용한다
  • 리스너, 콜백 등록 취소 : 리스너, 옵저버, 콜백은 항상 적절한 생명주기에서 등록을 취소하라. onPause, onStop에서 브로드캐스트 등록을 취소하는 것 등이다
  • 안 중요한 객체에 대한 WeakReference : 강한 참조가 불필요한 객체에는 WeakReference를 써라. 이렇게 하면 GC가 메모리 필요 시 해당 객체를 회수할 수 있다
  • 도구를 사용한 누수 감지 : 개발 중 메모리 누수를 식별하고 수정하려면 LeakCanary 같은 도구를 활용하라. 이 도구는 메모리 누수를 유발하는 객체, 이를 해결하는 방법에 대한 인사이트를 제공한다. 안드로이드 스튜디오의 메모리 프로파일러를 쓰면 끊김, 멈춤, 앱 충돌로 이어질 수 있는 메모리 누수, 이탈을 식별하는 데 도움을 받을 수 있다
  • 뷰에 대한 정적 참조 피하기 : 뷰는 액티비티 컨텍스트에 대한 참조를 유지해서 메모리 누수를 유발할 수 있으므로 정적 필드에 저장하면 안 된다
  • 리소스 닫기 : 파일 스트림, cursor, DB 연결 등 리소스는 더 이상 불필요할 때 항상 명시적으로 해제하라
  • 프래그먼트, 액티비티 잘 쓰기 : 프래그먼트를 과하게 쓰거나 액티비티 간 참조를 부적절하게 유지하지 마라. onDestroyView 또는 onDetach에서 프래그먼트 참조를 정리하라

 

설명 중 수정이 필요해 보이는 부분이 있다. Flow를 생명주기 인식 컴포넌트에 포함하고 있는데, Flow 자체는 생명주기라는 개념을 모르는, 데이터 스트림을 나타내는 인터페이스다. Flow를 구현하는 SharedFlow, SharedFlow를 구현한 StateFlow도 마찬가지다.

Flow가 생명주기를 인식하는 방법은 collect하는 방법에 달려있다. 흔히 액티비티에서 아래와 비슷한 코드로 뷰모델의 Flow에 담긴 값을 가져와서 사용할 것이다.

 

lifecycleScope.launch {
    viewModel.state.collect { value ->
        // 액티비티가 파괴되면 자동 취소
    }
}

// 아니면 repeatOnLifecycle도 같이 사용
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.state.collect { value ->
            // 액티비티가 STARTED 이상의 상태일 때만 Flow를 collect
        }
    }
}

 

뷰모델에선 viewModelScope를 사용할 텐데 이 스코프 자체가 생명주기 인식을 제공하기 때문에 이 스코프 안에서 Flow를 collect하면 뷰모델의 생명주기를 따르게 된다. 그래서 뷰모델이 삭제되면 같이 삭제된다. 코루틴 또한 마찬가지다.

액티비티면 보통 lifecycleScope를 사용하고, 프래그먼트에선 viewLifecycleOwner.lifecycleScope를 사용한다. 프래그먼트에서 lifecycleOwner를 못 쓰는 건 아니지만 프래그먼트와 액티비티 생명주기는 엄연히 다르기 때문에 viewLifecycleScope를 통해 lifecycleScope에 접근해 생명주기를 인식하는 게 좀 더 안전하다. 컴포즈라면 collectAsStateWithLifecycle을 쓸 수 있다.

반응형
Comments