react, kakao map api 사용 시 메모리 문제

HARIBO·2022년 2월 3일
1

문제

  • react와 kakao map api를 사용하여 지도를 랜더링 할 시
  • 확대, 축소, 이동을 할 때 전 지도가 잠깐씩 보이는 현상
  • 몇 분 정도 사용하면 앱이 멈춰버리는 현상

과정

  • 크롬 개발자 도구의 performance 탭을 이용해 기록을 확인했다. 중간에 휴지통 버튼(수동 garbage collection)을 두 번 눌러서 쓰이지 않는 메모리를 잘 회수하는지 확인했다

문제가 생긴 애플리케이션. GC를 수동으로 실행했음에도 Heap메모리가 줄어들지 않는다. summary를 보니 JS arrays 부분이 과도하게 많다.

다른 웹 애플리케이션. 파란 곡선이 증가하다가 뚝 떨어진다.

  • 크롬 개발자 도구의 Memory탭에서 초기 상태의 애플리케이션과 부하가 결렸을 때를 비교하기 위해 스냅샷을 두 개 찍었다.
    1. 두 스냅샷을 불러온 뒤, 비정상인 애플리케이션의 'Comparison'탭을 선택한다.
    2. 오른쪽에서 정상인 상태(snapshot 1)을 선택한다.
    3. 어떠한 객체가 더 생성되었는지 알 수 있었지만, 이 자료만 보고 무슨 객체인지 알기는 어려웠다.

  • allocation timelines를 찍어보았다. (record stack traces 옵션 체크). 'Allocation' 탭을 확인하고 size 순으로 내림차순 정렬하였다. 함수와 관련된 메모리 할당을 볼 수 있다고 한다.

    searchRoutes.tsx의 232 행 forEach 함수를 확인해 보았다. 해당 함수는 지도 이동, 지도 확대, 축소 이벤트가 일어날 때마다 몇 만번의 forEach반복문을 돌았다. 비효율적인 기능이지만 참조를 잘 못하는것 같지는 않았기에 메모리 누수의 원인은 아닌것 같았다.

원인

  • 개발자 도구의 Elements탭을 보고 알게 되었다.

    초록색 한 부분이 지도가 랜더링 된 DOM인데, useEffect 내부에서 랜더링을 하고 있었다. 지도 위에 마커들을 띄우기 위해 카카오 map객체를 사용해야 했고, 같은 useEffect함수 내에서 처리했었다. 문제는 state가 바뀔 때마다 useEffect함수가 실행돼, 전에 랜더링 되었던 지도는 그대로 남고, 새로 랜더링이 되고 있었다. 이 과정이 계속 반복되어 위 사진과 같이 지도가 그려진 DOM이 계속 생성되었고, 메모리 문제가 발생했다.

해결

  • kakao developers 답변을 참조해 맵 객체를 state로 관리했다.
  • 추가적으로 지도 위에 그리는 선, 폴리곤, 오버레이 등도 state로 관리해 불필요한 반복문을 돌지 않도록 했다.(위의 232행 forEach함수)
  • 특이한 점은, state로 관리하는 카카오 맵 객체에 relayout, setCenter같은 map API함수를 사용한다는 점이다. state는 불변성을 가져서 직접적으로 변경하지 않는 것으로 알고 있었는데, 이 경우에는 setter함수를 이용해 맵 객체를 복사해 사용하면 오히려 랜더링이 되지 않는 문제를 일으켰다.

참조
https://yceffort.kr/2020/07/memory-leaks-in-javascript#%EB%91%90-%EA%B0%9C%EC%9D%98-%EC%8A%A4%EB%83%85%EC%83%B7-%EC%B0%8D%EA%B8%B0
https://devtalk.kakao.com/t/topic/106470

0개의 댓글