프로그램에서 더 이상 쓰지 않는 메모리를 자동으로 찾아서 가져가는 것
ex)자바, C#, 자바스크립트 등
객체에 in-use flag를 두고, 사이클마다 메모리 관리자가 모든 객체를 추적해서 사용중인지 아닌지를 표시(mark), 그 후 표시되지 않은 객체를 삭제(sweep)하는 단계를 통해 메모리를 해제
한 객체를 참조하는 변수의 수를 추적하는 방법
변수의 레퍼런스가 복사될 때마다 : 레퍼런스 카운트++
객체를 참조하고 있던 변수의 값이 바뀌거나, 변수 스코프를 벗어나면 : 레퍼런스 카운트--
if 레퍼런스 카운트 === 0 (아무도 그 객체에 대한 레퍼런스를 가지고 있지 않을 때) : 그 객체와 관련한 메모리는 비울 수 있다
많은 시간이나 연산이 필요한 일에 대해 결과를 저장해두는 것
일시적인(temporarily) 특징이 있는 데이터를 저장하기 위한 목적으로 존재하는, 고속의 데이터 저장공간
-> 캐싱을 사용하면 이전에 검색하거나 계산한 데이터를 효율적으로 재사용
캐시의 데이터는 일반적으로 RAM(Random Access Memory)과 같이 빠르게 액세스할 수 있는 하드웨어에 저장됨
ex)
클라이언트: HTTP 캐시 헤더, 브라우저
네트워크: DNS 서버, HTTP 캐시 헤더, CDN, 리버스 프록시
서버 및 데이터베이스: 키-값 데이터 스토어(e.g. Redis), 로컬 캐시(인-메모리, 디스크)
Q : 크롬 브라우저 및 node.js의 v8 엔진은, 어떻게 가비지 컬렉션을 하고 있나요?
< V8 엔진의 메모리 구조 >
Resident Set - 실행 중인 프로그램은 V8 프로세스에서 할당된 일정량의 메모리로 표현됨
프로그램이 사용 가능한 것보다 더 많은 메모리를 힙에 할당하려고 할 때 메모리 부족 오류가 발생한다. 힙이 잘못 관리되면 메모리 누수가 발생할 수 있다.
V8 엔진은 가비지 컬렉션을 사용해 힙 메모리를 관리 한다.
참조 없는 객체(orphan object): 스택으로부터 (다른 객체 내부의 참조를 통해) 더 이상 직접 혹은 간접적으로 참조되지 않는 객체
가비지 컬렉터 : V8 프로세스에서 재사용하기 위해 사용되지 않은 메모리를 회수
-- New 영역(또는 Young 제너레이션) 관리
새 객체에 대한 공간을 예약하려고 할 때마다 증가하는 할당 포인터가 있다.
이 할당 포인터가 New 영역의 마지막에 도달하면, 마이너 GC가 발생한다.
New 영역의 구성: To 영역 / From 영역
대부분의 할당은 To 영역에서 만들어진다(항상 Old 영역에서 할당된 실행 코드와 같은 특정 종류의 객체 제외)-> To 영역이 가득 차면 마이너 GC가 발생한다
-- Old 제너레이션 영역 관리
메이저 GC는 Tri-color(흰색-회색-검은색) 마킹 시스템을 사용.
따라서 메이저 GC는 세 단계의 프로세스를 거치며, 세 번째 단계는 조각화 휴리스틱(fragmentation heuristic)에 따라 실행
마킹(Marking): 두 알고리즘의 공통적인 첫 번째 단계로, 가비지 컬렉터가 어떤 객체가 사용중인지 식별한다. 사용중이거나 GC 루트(스택 포인터)에 재귀적으로 도달할 수 있는 객체들은 활성 상태로 표시된다. 마킹은 기술적으로 힙 메모리를 방향 그래프(directed graph)로 간주해 깊이 우선 탐색(depth first search)를 수행한다.
스위핑(Sweeping): 가비지 컬렉터가 힙 메모리를 순회하면서 활성 상태로 표시되지 않은 객체들의 메모리 주소를 기록한다. 이 공간은 이제 사용 가능한 목록(free-list)에서 사용 가능하다고 표시되며 다른 객체들을 저장하는 데 사용될 수 있다.
압축(Compacting): 스위핑이 일어난 다음, 필요하다면 모든 활성 상태의 객체들이 함께 이동될 것이다. 압축 단계는 조각화를 줄이고 새 객체들에 대한 메모리 할당 성능을 증가시킨다.
메이저 GC는 GC를 수행하는 동안 애플리케이션 실행을 멈추므로 stop-the-world GC
라고도 한다.
- 많은 마이너 GC 주기를 거치고 Old 영역이 거의 다 찼으며 V8이 "메이저 GC"를 발생시킴.
- 메이저 GC는 스택 포인터에서 시작해 재귀적으로 객체 그래프를 순회하면서, Old 영역 내 메모리를 사용한 객체와 남아있는 객체를 가비지로 표시
- 동시 마킹이 완료되거나 메모리 제한에 도달하면 GC는 메인 스레드를 사용하여 마킹의 마지막 단계를 수행한다. 이 때 일시 정지 시간이 발생
- 메이저 GC는 동시 스위프 스레드를 사용해 모든 참조 없는 객체들의 메모리를 사용 가능한 상태로 표시한다. 또한 조각화를 피하기 위해 관련 메모리 블록을 동일한 페이지로 이동하도록 병렬 압축 작업도 발생한다. 포인터들은 이 세 단계를 통해 갱신된다.