[Trouble Shooting] - 메모리 누수해결하기 -작성중

Hunter Joe·2025년 11월 23일

→←↑↓


채팅창input 태그에 텍스트를 작성하고 있던와중에 텍스트가 끊기듯이 작성하길래
메모리 사용량을 확인해봤더니 900MB으로 많은 사용량을 차지하고 있음

이렇게 개발중에 체감될 정도의 메모리 누수는 처음 겪어봐서 자세하게 어떻게 해결했는지를 담아볼 예정이다.

누수 발견

메모리 누수 유형

NOTE
참고 : Google Developer
Memory Bloat → 사이트가 점점 더 많은 메모리를 사용한다면 메모리 누수가 발생한 것임 하지만 Memory bloat는 정확한 수치가 없고 RAIL모델을 활용해서 사용자에게 집중해야함

내 프로젝트의 경우 직관적으로 1번, 3번이 가장 유력하다.
→ 직감을 도구를 활용해 구체화 해보자

  • Chorme Task Manager
  • Chrome devtools의 Memory, performance

크롬 Task Manager

크롬 devtool로 확인하기 / Record

TIP

  • 성능 기록을 시작하기 전과 종료할 때, 수동으로 가비지 컬렉션을 한 번씩 실행해주는 게 좋아요. 녹화 중에 빗자루 아이콘(Collect garbage)을 누르면 가비지 컬렉션을 강제로 수행할 수 있어요.

(위 사진은 Performance 탭에서 Memory 부분을 녹화한 예시)

일단 분석을하고 문제가 뭔지를 알려면 그림에 보이는 JS heap, Document, Nodes, Listener가 뭔지부터 알아야겠지?
↓↓↓↓↓ 알아보자

🔵 JS heap

  • JavaScript 엔진(V8)이 실행될 때 사용되는 메모리 영역 중 하나로 주로 객체, 배열, 함수 등 동적으로 생성되는 데이터를 저장하는 공간
  • JavaScript에서 원시 값은 보통 스택이라는 다른 메모리 영역에 저장되는 반면 크기가 가변적이고 참조를 통해 접근하는 참조 타입은 JS힙에 저장됨
  • 파랑선이 하락하는 부분이 GC가 작용하는 부분임

🟢 Nodes

  • 노드란 웹페이지를 구성하는 HTML element 하나하나를 의미
  • 페이지에서 element를 제거했음에도 불구하고 해당 노드를 참조하는 JavaScript 변수나 클로저가 남아 있으면 메모리에 누적될 수 있다.메모리 누수의 원인

🟡 Listeners

  • 리스너는 웹 페이지에서 특정 이벤트가 발생하기를 기다리고 있다가 발생하면 미리 정의된 함수(주로 콜백함수)를 실행하도록 등록된 요소

  • 어떤 <div>click과 같은 이벤트 리스너를 등록했고 후에 해당 <div>를 제거했음에도 JavaScript 코드 어딘가에 해당 리스너에 대한 참조가 남아 있다면 리스너와 연결된 <div> 노드는 GC에 의해 제거되지 않음. 메모리 누수의 원인

🔴 Documents

  • 웹 페이지의 개수

Performance 녹화 + heap snapshot


프로젝트의 총 5번의 측정기록

1-2번 그래프: JS heap, Nodes, Listeners가 증가. ← 메모리 누수
3번 그래프: JS heap, Listeners 증가.
4-5번 그래프 : 애매하다고 판단

이렇게 Performance 탭에서 메모리를 어떻게 사용중인지 녹화하는것은 애매한 부분이 있어서 좀 더 확실하게 하기 위해 heap snapshot을 찍어보기로 하였다.

heap snapshot


스냅샷 또한 73.7에서 시작해 94.1까지 찍을 때마다 증가하고 있다. 더 볼것도 없다 걍 메모리 누수다

어디서 메모리 누수가 날까?

녹화 + heap snapshot으로 내 프로젝트에서 메모리 누수가 난다는 것은 확실해졌다.
그럼 이제 어디부분에서 메모리 누수가 난다는 걸까? 그리고 어떻게 찾아야 할까?


(Snapshot1)

(Snapshot Comparison: snapshot5(base) vs snapshot1(compare) )

메모리를 가장 많이 점유하고 있는 누수 원인은 (string)과 Error 객체이다.
snapshot1 ~ snapshot5까지 진행하는 동안 새로운 문자열이 4556개나 생성되었으며 GC에 의해 해제되지 않고 메모리에 남아 있다.
또한 Error 객체 또한 9547개나 증가했으며 이는 내가 인지하지 못하는 사이 어디선가 예외나 경고가 발생하고 있고 해당 Error 객체들이 어딘가에 참조되어 메모리에 쌓이고 있다는 뜻이다.

문제는..
모르겠다. 정확하게 메모리 누수가 나는 곳이 어디인지 모르겠다. 그래서 다음과 같은 방법을 써서 진단해보기로 했다.

많은 작업량을 처리하고 있는 Task를 보면 useSocketManagersetTickerStream에서 대용량 트래픽이 발생하고 있다는 것을 확인 할 수 있다.

해당 코드에서 메모리 누수를 막을 수 있지 않을까해서 일단 수정해보겠다.

현재까지 useSocketManagersetTickerStream코드는 수정을 마쳤다.

  • setTickerStream의 devtools 코드제거
  • useSocketManager모든 소켓 리스너에 cleanup 함수

참고 자료

https://leetrue.hashnode.dev/memory-leak-chrome
https://blog.eunsukim.me/posts/debugging-javascript-memory-leak-with-chrome-devtools

profile
Async FE 취업 준비중.. Await .. (취업완료 대기중) ..

0개의 댓글