본문 바로가기
개발

[안드로이드 코틀린] leakcanary(리크카나리)를 써보자

by kks950115 2024. 3. 26.
728x90

어제 profiler로 메모리 리크를 해결하기 위해 삽질을 했지만 실패했다.의심가던 전역변수를 모두 없앴는데도 리크가 일어나는 것이다....  뭔가 내가 놓치고 있는게 있나해서 이거 뭐지하다가 튜터님한테 도움을 청하러 갔다. 리크카나리라는 라이브러리가 메모리 리크를 잡는데 좋다고 추천해주셨다.  맵 프래그먼트인거는 알겠는데 그래서 어디가 잘못됐는데?란 상황에 봉착했을 때, 조금 더 자세하게 문제의 원인을 특정해줄 수 있다고 한다.

 

리크 카나리를 써보자. 우선 빌드 그래들에 추가한다.

dependencies {
	debugImplementation ("com.squareup.leakcanary:leakcanary-android:3.0-alpha-1")
}

 

디버그임플레이션?은 뭐지 했는데 종류를 찾아보니 여러가지가 있었다.

 

1. implementation : 항상 적용.

2. debugImplementation : 디버그 빌드 시에만 적용.

3. releaseImplementation : 릴리즈 빌드 시에만 적용.

4. testImplementation : 테스트 코드를 수행할 때만 적용.

 

현재 나는 디버그로 하고 있다. 저 상태로 앱을 실행하면 에뮬레이터 바탕화면에 

 

Leaks 라는 이름의 새 아이콘이 생긴다. 

그리고 메모리 리크 의심이 가는 곳을 반복해서 실행해주자.

그러면 이런 로그가 뜨는 것을 확인할 수 있다.

하다보면 알림이 뜰 것이다.

아이콘을 클릭해서 들어가면 아래 화면이 뜬다.

 

이전에 한 내역들이 같이 보이는데 이건 무시. new라고 써져 있는 게 메모리 리크로 의심되는 영역이다. 

 

맵 프래그먼트에서 뷰모델 쪽이 문제 인 거같은데.... 스택읽는 법을 모르겠다. 그냥 써져있기론 프래그먼트를 파괴하란 콜백을 받았지만  프래그먼트 수명주기와 충돌이 난다 상태가 정의되어 있다.란 말이 써져있는 거 같은데.....

 

이 문제는 해결하면 글을 수정하겠다.

 

추가 수정)

문제를 해결했다. 리크카나리에 전역변수에 문제가 있다고 나와서 그 부분을 유의깊게 보았다. 그러다가 뷰모델 사용법에 대해 gpt로 검색하다보니 의심가는 부분을 발견했고 정답이었다.

private fun initViewModel() = with(viewModel) {

        campMarker.observe(viewLifecycleOwner) {
            if (campList.value?.isNotEmpty() == true) {
            	//이 부분이 문제였다. 수정 전 코드다.
                campDataList = campList.value!!
                val tempList = mutableListOf<Marker>()
                //마커에 클릭리스너 추가
                for(campMarker in campMarker.value!!){
                    campMarker.setOnClickListener {
                        val campData = campMarker.tag as LocationBasedListItem
                        val tag = campData.induty
                        //..
                }

            }
        }
    }
    
    
    //수정 후
    val campdatalists = it
    campDataList = campdatalists

원인은 뷰모델에 있는 campList 값을 campList.value!!로 프래그먼트에서 직접 호출하여 사용했기 때문이었다.

그래서 직접 호출하지 않고 변수에 담아서 사용하니 메모리 리크가 사라졌다. 

거기에 더해 마커 데이터와 캠핑장 데이터를 두 개 뷰모델에 갖고 있는 것이 중복 데이터라 생각하여 뷰모델에는 캠핑장 데이터만 갖고 있고 마커 데이터는 뷰에서 그때그때 필요할 때마다 생성하는 것으로 수정했다.

다른 메소드에도 직접 호출하여 사용했었는데 이 부분도 모두 변수에 담아서 사용하는 걸로 바꾸니 거짓말처럼 메모리리크가 사라졌다.

 

뷰모델을 처음 써봐고 구현에만 급급하다보니 일어난 실수였다. 

728x90
반응형

댓글