let HEAP = [];
const A = {
language: 'JavaScript'
}
const B = {
language: 'Rust'
}
const C = {
language: 'Elm'
}
const D = {
language: 'GoLang'
}
변수 HEAP를 힙 메모리 공간이라고 가정합니다. 상수 A에는
JavaScript
가 B에는Rust
, C에는Elm
, D에는GoLang
등 각각 문자열이 값으로 저장되어 있습니다.
HEAP.push(A);
HEAP.push(B);
HEAP.push(C);
HEAP.push(D);
HEAP 메모리 공간에 A부터 D순서대로 각각의 객체를 배열의 요소로 추가합니다.
[
{ language: 'JavaScript', B: { language: 'Rust', C: { language: 'Elm', D: { language: 'GoLang' } } } },
{ language: 'Rust', C: { language: 'Elm', D: { language: 'GoLang' } } },
{ language: 'Elm', D: { language: 'GoLang' } },
{ language: 'GoLang' }
]
다음과 같이 HEAP 메모리 공간에 저장되게 됩니다.
const root = () => HEAP[0];
A.B = B; // A 객체는 B객체를 참조
B.C = C; // B 객체는 C객체를 참조
C.D = D; // C 객체는 D객체를 참조
함수 표현식으로 작성된
root 함수
는HEAP 메모리의 최상단 요소
를 가리킵니다. 각각의 객체는 HEAP 메모리에 다음 요소를 참조합니다. 따라서A 객체의 B
는 B 객체를 참조하고B 객체의 C
는 C 객체를 참조하고C 객체의 D
는 D 객체를 참조합니다.
const gc = () => {
mark();
sweep();
}
가비지 컬렉터의 역할을 하는 gc 함수는 mark 과정을 수행하는
mark 함수
와 sweep 과정을 수행하는sweep 함수
를 각각 호출합니다.
const mark = () => {
let reachables = [root()];
while (reachables.length) {
let current = reachables.pop();
if (!current.__markBit__) {
current.__markBit__ = 1;
for (let i in current) {
if (typeof current[i] === 'object') {
reachables.push(current[i]);
}
}
}
}
}
mark 함수는 mark 과정을 수행합니다. 즉 HEAP 메모리 공간을 순회하면서 HEAP 배열의 요소에 값으로 1을 갖는 키 markBit를 추가합니다. root 함수는 HEAP 메모리의 최상단 요소를 반환하므로 reachables 변수는 HEAP 메모리의 최상단 요소를 갖는 배열이 됩니다. 이 변수를 반복문으로 돌면서 변수에 담긴 HEAP의 최상단 요소를 다시 current 변수에 담습니다. 만약 current 변수에 markBit가 존재하지 않는다면 아직 순회하지 않은 요소이므로 1을 값으로 갖는 키 markBit를 요소로 추가합니다, 이 때
current[i]
가 객체일 경우 reachables 변수에 추가합니다.
✅ root가 접근할 수 없는 객체
여기서
current[i]
는 HEAP의 최상단 요소부터 시작해 각 요소가 참조하고 있는 객체를 가리킵니다. 위에서 A는 B 객체를 참조하므로 B객체를 변수reachables
에 담고 B 객체는 C 객체를 참조하기 때문에 C 객체를reachables
에 담고 다시 C 객체는 D 객체를 참조하기 때문에 D 객체를reachables
에 담습니다. 만약 HEAP 최상단 요소가 아무 객체도 참조하고 있지 않으면서 그 아래 요소들이 다른 객체 요소를 참조하고 있는다고 해도 최상단 요소가 아무 값도 참조하고 있지 않기 때문에 반복문이 종료되어reachables
에 최상단 요소를 제외한 하위 요소들이 참조하는 객체들을 담지 않게 됩니다.
[
{
language: 'JavaScript',
B: { language: 'Rust', C: [Object], __markBit__: 1 },
__markBit__: 1
},
{
language: 'Rust',
C: { language: 'Elm', D: [Object], __markBit__: 1 },
__markBit__: 1
},
{
language: 'Elm',
D: { language: 'GoLang', __markBit__: 1 },
__markBit__: 1
},
{ language: 'GoLang', __markBit__: 1 }
]
순회 결과 다음과 같은 값을 반환합니다.
const sweep = () => {
HEAP = HEAP.filter(current => {
if (current.__markBit__ === 1) {
current.__markBit__ = 0;
return true;
} else return false;
});
}
const main = () => {
gc();
}
main();
sweep 함수는 HEAP 메모리 공간 안에 존재하는 각 객체 요소들이
markBit
를 가지고 있다면markBit
의 value를 0으로 바꿔 저장하게 됩니다. 즉 HEAP 메모리 공간에서 최상단 요소부터 시작하여 참조하거나 참조되는 객체들이 존재한다면 mark 함수를 호출한 결과로 markBit를 가지고 있을 것이며 이 markBit를 0으로 재할당하게 됩니다.
'use strict'
let HEAP = [];
const A = {
language: 'JavaScript'
}
const B = {
language: 'Rust'
}
const C = {
language: 'Elm'
}
const D = {
language: 'GoLang'
}
HEAP.push(A);
HEAP.push(B);
HEAP.push(C);
HEAP.push(D);
const root = () => HEAP[0];
A.B = B; // A 객체는 B객체를 참조
B.C = C; // B 객체는 C객체를 참조
C.D = D; // C 객체는 D객체를 참조
const gc = () => {
mark();
sweep();
}
const mark = () => {
let reachables = [root()];
while (reachables.length) {
let current = reachables.pop();
if (!current.__markBit__) {
current.__markBit__ = 1;
for (let i in current) {
if (typeof current[i] === 'object') {
reachables.push(current[i]);
}
}
}
}
}
const sweep = () => {
HEAP = HEAP.filter(current => {
if (current.__markBit__ === 1) {
current.__markBit__ = 0;
return truel
} else return false;
});
}
const main = () => {
gc();
}
main();