메모리 누수를 해결해 보자

혜성·2024년 4월 22일
0
post-thumbnail

문제의 시작

최근 빈번하게 사이트 사용중 장시간 탭을 열어두는 경우 사이트의 속도가 저하되며 사용이 불편해지는 문제가 발생해 성능저하의 원인 파악이 필요해 졌습니다. 따라서 두 가지 원인을 예측후 확인에 들어갔습니다.

  1. react-query fetch 옵션
  2. 메모리 누수

1차적으로 브라우저를 사용하지 않다가 다시 포커싱했을때에 관한 성능저하 상황을 전달받아 react-query의 캐시나 윈도우 포커스시 fetch옵션 등을 점검해 보았을때 문제가 발견되지 않았습니다.

따라서 메모리 누수가 성능저하의 원인으로 판단했고, 이를 파악하는 방법과 해결하는 과정에 대해 탐색이 필요했습니다.


메모리 누수의 징후

  1. 속도 저하: 애플리케이션 작업의 긴 세션(몇 시간 또는 하루일 수 있음) 후에 UI가 느려지고 느려집니다.
  2. 웹 페이지가 충돌합니다.
  3. 앱이 자주 일시 중지됩니다.
  4. JS 힙이 시작된 것보다 높게 끝납니다.
  5. 노드 크기 및/또는 리스너 크기가 증가하는 것을 볼 수 있습니다.

징후 확인

1~3 번의 항목은 테스트를 바탕으로 포착 가능한 징후가 아닌 사이트 사용에서 확인 가능한 징후입니다.
실제 TFTPS를 사용하며 전달받은 문제와 메모리 누수의 징후가 일치하는 경우가 매우 많았습니다.

  • 세션의 길이가 길어짐에 따라 사이트의 속도가 저하되는 문제가 발생
  • 장시간 유지한 탭이 있을시 브라우저 정지

따라서 브라우저의 개발자 도구를 활용해 실제 메모리의 사용을 파악하고자 하였습니다.


메모리 누수의 파악하기

Performance (사이트 성능 측정)

메모리 누수가 징후가 포착되며 실제 누수가 발생중인지 파악하기 위해 크롬 개발자도구 Performance Timeline Record를 활용합니다.

  1. 개발자도구 성능 탭 활용
  2. 성능 탭의 메모리 체크박스 체크후 성능측정 시작
  3. 메모리 누수가 의심되는 동작 시행
  4. 측정결과 그래프 확인

  • JS Heap 용량(파란선)
  • Documents (빨간선)
  • DOM Nodes (초록선)
  • 이벤트 리스너 (주황선)

총 2분 녹화결과 JS 힙, Documents, 노드, 리스너 모두 측정 시작보다 높게 끝나며 우상향 하는것을 확인 ⇒ 메모리 누수가 발생중

메모리 누수가 발생하는 것을 확인하였습니다. 다음으로 어떤 메모리가 시간이 지남에 따라 할당되고 해제되는지를 확인하고자 하였습니다.

Heap Snapshots (메모리 사용 확인)

실제 누수가 발생하는 지점을 확인하기 위해 크롭 개발자 도구 메모리 패널의 기능을 활용합니다.
연속적인 힙 스냅샷을 찍고 이를 비교하여 페이지에서 얼마나 많은 메모리가 할당되고 소비 되었는지에대한 정보를 얻을 수 있습니다.

  1. 개발자도구 메모리 탭 활용
  2. 힙 스냅샷 촬영을 통한 비교
  3. 스냅샷 1 촬영 후 일정 시간 경과 후(메모리 누수가 의심되는 동작 시행후) 스냅샷 2 촬영
  4. 스냅샷 1 ~ 스냅샷 2 사이 할당된 객체를 살펴보기
  5. #New, #Deleted 확인
  6. 확인결과 광고관련 객체가 다수 발견

성능 측정과 스냅샷 비교 그리고 광고객체

스냅샷 비교 분석 결과 광고와 관련된 메모리 객체가 다수 반복적으로 발견됨을 확인했습니다.

따라서 광고가 원인이라 의심하고, 실제 광고 유무에 따라 사이트 성능에 차이가 있는지 확인했습니다.

  1. 광고 스크립트 제거 전후 메모리 힙 그래프 (2분)

    • 제거 전

    • 제거 후

    광고 스크립트 제거전후 성능을 확인한 결과 광고 제고후 메모리 힙 그래프의 변화를 통해 메모리 누수의 원인이 광고 관련 기능임을 최종적으로 확인했습니다.

    현재 사이트의 광고동작은 페이지 라우팅이 발생하거나 30초를 주기로 광고를 불러와 컴포넌트를 갱신하는 방식입니다.

    • 페이지에서 아무런 동작을 취하지 않을시 20초 ~ 30초를 주기로 메모리 힙이 증가
    • 페이지를 라우팅 할때 역시 메모리 힙이 증가

    실제 광고동작 사이클과 유사한 패턴으로 메모리 힙이 증가하는 모습을 확인했습니다.

  2. 메모리 스냅샷 1 과 2 사이 할당된 객체 정보

  3. 광고의 add, remove 동작시 배열내에 광고 Ref를 배열내에 push, pop 하는 방식으로 동작하지만 해당 과정에서의 문제가 발생하는것으로 예측했습니다.


원인파악 결과

  • 메모리 힙 스냅샷 분석 결과 광고와 완련된 객체가 다수 파악
  • 광고 컴포넌트의 동작 방식 점검
  • 인스트림 광고 컴포넌트의 경우 광고배열에 요소를 push 해줄 필요가 없지만 push만 실행 하고있었고
    반대로 광고가 언마운트 될때 remove해주는 코드는 기존에 제거를 해둔 상태
  • 따라서 인스트림 광고 컴포넌트 내부의 광고배열 push 코드 제거

성능 측정과 스냅샷 비교를 통해 광고와 관련된 기능에 문제가 있음을 파악하고 광고 컴포넌트의 메모리 낭비를 유발하는 코드를 수정하였습니다.

  • 수정후 메모리 힙 사용 그래프

코드 수정과 배포가 완료된 사이트의 메모리 힙 사용량 그래프 입니다. 기존과 다르게 인스트림광고 요소정보의 push만 동작하고 remove하는 동작은 없는 코드를 제거했을시 메모리 힙 사용량 그래프가 약 30초 주기로 업데이트되는 광고동작에 따라 우상향 하지 않고 안정된 모습을 보여주는것을 확인했습니다.


마치며

이번 메모리 누수 케이스를 경험하며 메모리 누수 해결에는 크게 다음과 같은 과정이 필요하다는 것을 알게되었습니다.

  1. 메모리 누수 징후 파악하기
    1. 사이트의 성능 저하 등 메모리 누수 징후가 있는지 확인합니다.
    2. 메모리 누수를 발생시키는 동작을 파악합니다.
  2. 메모리 누수 발생 확인하기
    1. 개발자도구 성능 탭의 성능 측정을 활용합니다.
    2. 메모리 누수가 의심되는 동작을 측정하는동한 시행하며 프로파일링을 진행합니다.
    3. 그래프 분석을 통해 메모리 누수 발생을 확인합니다.
  3. 메모리 누수 지점 파악하기
    1. 개발자도구 메모리 탭의 스냅샷을 활용합니다.
    2. 스냅샷 촬영과 비교를 진행합니다.
    3. 타임라인 할당 계측을 진행합니다.
    4. 힙 스냅샷의 시간별 비교를 통해 새롭게 메모리에 할당된 객체를 확인합니다.
    5. 객체 정보 확인을 통해 메모리 누수의 원인을 파악합니다.

추후 비슷한 문제를 겪게될 시 위와 같은 과정을 거쳐 메모리 누수의 발생 확인과 해결에 더 빠른 대응이 가능하리라 생각합니다.

0개의 댓글