pile·
프론트엔드·카카오 엔터테인먼트 FE카카오 엔터테인먼트 FE·

자바스크립트 v8 엔진의 가비지 컬렉션 동작 방식

자바스크립트 V8 엔진이 메모리를 어떻게 관리하는지, 마이너/메이저 GC의 내부 알고리즘을 단계별로 해설한다. 브라우저·Node.js 성능 튜닝의 기반이 되는 지식으로, 메모리 누수 원인 분석과 GC 부담 최소화 코드 작성에 직접 활용할 수 있다.

핵심 포인트 - V8 메모리 구조: Resident Set → 스택(정적) + 힙(동적). 힙은 New Space(Young generation)와 Old Space(Old generation)로 분리 - New Space: 1~8MB, From/To 두 semi-space로 구성. 마이너 GC(Scavenger)가 담당하며 단명 객체 대부분을 여기서 처리 - Old Space: Pointer Space(다른 객체를 참조하는 객체)와 Data Space(문자열·숫자 등 원시값)로 구분. 메이저 GC(Mark-Sweep-Compact)가 담당 - Generational Hypothesis: 새로 생성된 객체일수록 빠르게 쓸모없어질 가능성이 높다는 가설이 세대별 GC 설계의 근거 - 마이너 GC 동작: From Space 순회 → 살아있는 객체를 To Space로 대피(Evacuation) → From/To 역할 교환. 2번 살아남은 객체는 Old Space로 승격(Promotion) - 메이저 GC: Tri-color 마킹(white=미방문, gray=방문중, black=완료) + DFS 순회로 도달 가능 객체 식별 → Sweep으로 white 객체 반환 → Compact로 단편화 해소 - Orinoco 프로젝트: Parallel GC(메인스레드+헬퍼스레드 동시), Incremental GC(작업 분할), Concurrent GC(백그라운드 처리)로 stop-the-world 시간을 획기적으로 단축

상세 정리 - 스택은 함수 콜프레임·원시값·참조 포인터를 저장하며 함수 종료 시 자동 해제 - 힙은 참조 타입(객체·배열·함수·클로저) 저장소로 GC가 관리 - New Space의 From→To 대피 후 From Space를 전체 초기화하므로 단편화 없음 - 마이너 GC는 포인터 업데이트도 동반해 Old Space에서 New Space를 가리키는 레퍼런스를 Write Barrier로 추적(Remembered Set 활용) - 메이저 GC의 Compact 단계는 비용이 크므로 단편화가 심한 페이지에만 선택적으로 적용 - Incremental GC: GC 작업을 잘게 쪼개 메인스레드와 인터리브. 개별 pause 시간 감소 - Concurrent GC: 헬퍼스레드가 백그라운드에서 마킹·스윕을 처리해 메인스레드 정지 최소화 - 클로저는 외부 함수의 스코프를 참조해 Old Space 승격 가능성이 높음 - WeakMap·WeakRef 사용 시 GC 수집 대상으로 남아 메모리 압박 완화 - 대용량 배열을 null 처리하지 않으면 Old Space에서 메이저 GC 대상이 되어 pause spike 유발 가능

왜 읽나: V8 GC의 세대별 구조와 Orinoco 최적화를 이해하면 Node.js·브라우저 환경에서 성능 병목을 정확히 진단하고 GC 친화적 코드를 작성할 수 있다.

카카오 엔터테인먼트 FE
카카오 엔터테인먼트 FE 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 프론트엔드·여기어때 (GC컴퍼니)여기어때 (GC컴퍼니)·

    항공 프론트엔드 구축기 (7/10): 창구를 하나만 두었습니다

    여기어때 항공 서비스 프론트엔드가 웹과 앱 웹뷰 두 환경에서 동일한 함수 호출로 동작하는 앱 브릿지 추상화 레이어를 설계한 과정을 다룬다. iOS·안드로이드 규약 차이와 "웹에 존재하지 않는 브릿지를 어떻게 호출하나"라는 문제를 단일 추상화 층으로 해결한 구현 사례다.

    요약 이어보기
    #react#typescript#webview+2