문제상황
기본적으로 현재 진행중인 프로젝트에서 유저가 보유하고 있는 선수 카드 리스트는 최적화를 적용해 앱 진입 시점에 한 번 받은 뒤 캐싱해서 사용한다. 이후 리스트에 업데이트가 있을 경우 해당 부분만 새로 업데이트해주는 전략을 가져가고있다.
선수카드는 만 장이 넘어가게 소유할 수 있고, 개별 카드의 이미지도 무겁고 리소스가 큰 탓에 메모리, 네트워크 요청에 많은 부담이 있을 수 있어 위와 같은 정책을 선택했고 렌더 또한 가상화 라이브러리를 사용해서 스크롤에 따라 필요한 순간 동적으로 렌더하고 있었다.
하지만 마찬가지로 선수 리스트를 보여줘야하는 특정 컨텐츠에서 문제 상황이 발생했다. 해당 컨텐츠에서는 기획상 (언젠간 바꿔야 하는 부분이였지만) 결론적으로 모든 선수 리스트를 한 번에 받아오며, 당시 상황상 다른곳에서 공통적으로 사용하고 있는 가상화 라이브러리 적용이 힘들어 최적화 없이 단순 렌더해주는 상황이였다. 수많은 선수 이미지 네트워크 요청이 있었으며 스크롤을 빠르게 계속해서 내릴 경우 당연히 메모리 해제 없이 힙 메모리에 계속해서 데이터가 쌓이는 상황이였다.
QA때도 올라오지 않았던 이슈인데, 기본적으로 선수카드가 10000명 이상 넘어가는 계정으로 테스트를 돌리신 분이 없었던 것 같다. 우연히 특정 계정에서만 발생한 문제이고 재현도 100%되는것이 아니라 여러번 테스트 해본 결과 "10000장 이상의 선수카드를 보유하고 있는 계정으로 선수 리스트를 렌더하는 페이지(최적화가 안되어있는)에서 스크롤을 빠르게 계속해서 내리는 경우" IOS에서만 웹뷰 인스턴스가 강제종료되며 앱이 꺼지는 현상이 발생하고 있었다. 크로스 브라우징 이슈 관련해서는 조사 결과 Safari와 크롬의 가비지 컬렉션 정책이 달라 발생했던 것이였다. 가상화 라이브러리를 사용한 선수카드 리스트에서는 메모리 사용을 조절할 수 있는데, 해당 컨텐츠에서는 가비지 컬렉터가 동작하지 않았고 xcode 빌드에서 로그를 찍어본 결과 웹뷰 인스턴스가 죽은 직전 상황에
1. 과도한 네트워크 요청
2. 메모리 한계치
관련 로그가 찍혀있는것을 확인할 수 있었다. 개발자도구에서 확인되고 있는 현상이랑 정확하게 일치했다.
해결과정
우선 메모리 누수, 가비지 컬렉션에 대해 조금 더 자세하게 이해하기 위해
https://ui.toast.com/posts/ko_20210611
해당 블로그를 참고했다.
사실 해결 방법은 정해져있었다. 사용하지 않는 메모리를 제거하는 것, 캐싱 및 최적화를 통해 네트워크 요청을 줄이는 것
API가 수정되었고 결론적으로는 원래 사용하던 가상화 리스트 컴포넌트를 확장하는 방법으로 해결했다.
하지만 앱이 죽어있는채로 있는것은 막아야했고 응급처치는 필요했으니,,,,
onContentProcessDidTerminate시webView에서 webView를 reload하는 코드를 추가하는 방향으로 조치를 취했다.
느낀점
많은 양의 무거운 데이터를 다룰때는 코드 한 줄을 짜더라도 많은 생각과 신중함이 필요하다는것을 다시 한 번 느꼈다.
안일하게 넘어간 부분 때문에 앱 자체가 죽어버리는것을 보고 메모리 누수를 항상 염두해두어야겠다고 생각했다.
단순 로컬에서의 테스트에서 문제가 없었다고 정말 문제가 없는 것은 아니였다.
무수히 많은 유저가 있고 이에 따르는 수많은 테스트 케이스가 있다는 부분을 항상 명심하고 개발을 해야겠다.
추가적으로 console.log, setInterval 사용 시에도 메모리 누수 위험이 있고, console.log 사용은 되도록 지양하며 setInterval 함수 사용시 더욱 신중하게 타이머를 해제해야겠다고 생각했다. (setTimeout도 최대한 사용을 지양하자.)
당신이 모르는 자바스크립트의 메모리 누수의 비밀
크롬 개발자도구로 하는 디버깅과 해결책을 찾아서!
ui.toast.com
'React-Native' 카테고리의 다른 글
[React Native] React Navigation (0) | 2023.07.19 |
---|---|
[React Native] RN에서 Webview 사용하기 (0) | 2023.07.19 |
[React Native] Mac 개발환경 세팅 (0) | 2023.07.19 |