먼저, 아주 간단히 핵심만 말해보자면 자바스크립트는 객체가 생성되었을 때 자동으로 메모리를 할당하고 쓸모 없어졌을 때 자동으로 해제하는 기능이 있는데요. 이러한 기능을 가비지 컬렉션이라고 합니다 😎
그럼 먼저 메모리에 대해 한 번 짚어볼까요? 우선 메모리 생존 주기는 어떤 프로그래밍 언어든 관계 없이 아래와 같이 이루어져요.
여기서 메모리 사용(2번)은 개발자가 직접 코드를 짜면서 건드리기 때문에 명시적으로 사용됩니다. 그렇지만 메모리를 해제할 때(3번)는 자바스크립트가 자동으로(암묵적으로) 메모리를 해제하게 됩니다.
그렇다면 더 이상 필요하지 않은 객체들을 어떻게 자동으로 처리할 수 있는 것일까요?
바로 자바스크립트 엔진 내의 가비지 컬렉터에서 메모리 관리를 수행하기 때문입니다! 엔진 내에선 가비지 컬렉터가 끊임없이 동작하기 때문에 모든 객체를 모니터링 할 수 있는 것이죠.
아래에서 가비지 컬렉션(터)에 대해 더 자세히 알아보아요. 😎
계속 말했지만, 자바스크립트에서는 가비지 컬렉터에 의해 메모리를 자동으로 관리해줍니다.그렇다면 가비지 컬렉션은 할당된 메모리 블록이 더 이상 필요하지 않은지 어떻게 판단할 수 있는 걸까요?
자바스크립트는 메모리 관리를 수행할 때 도달 가능성(reachability) 이라는 개념을 사용합니다. 도달 가능한 값은 메모리에서 절대 삭제되지 않습니다.
도달 가능성(reachability)
도달 가능한 값
root
라고 부름
root
가 참조하는 값이나 체이닝으로 루트에서 참조할 수 있는 값예를 들어 전역 변수에 객체가 저장되어 있다고 가정했을 때, 이 객체의 프로퍼티가 또 다른 객체를 참조하고 있다면 프로퍼티가 참조하는 객체는 도달 가능한 값이 됩니다
다양한 예시들을 통해 개념들을 다시 한 번 짚어봅시다 ! 🤜🏻
// user엔 객체 참조 값이 저장됨
let user = {
name: "John"
};
user
는 {name:”John”}
이라는 객체를 참조하고 있습니다.name
은 원시값을 저장하고 있기 때문에 객체 안에 표현합니다.만약 이 상태에서 user의 값을 다른 값으로 덮어쓰면 참조(화살표)가 사라지게 됩니다.
user = null;
// user엔 객체 참조 값이 저장
let user = {
name: "John"
};
let admin = user;
user = null;
admin
도 다른 값(null 등)으로 덮어쓰게 된다면 John은 메모리에서 삭제 될 수 있습니다.function marry(man, woman) {
woman.husband = man;
man.wife = woman;
return {
father: man,
mother: woman
}
}
let family = marry(
{name:"John"},{name:"Ann"}
);
delete family.father;
delete family.mother.husband;
외부로 나가는 참조는 도달 가능한 상태에 영향을 주지 않습니다.
이제 John은 도달 가능한 상태가 아니기 때문에 메모리에서 제거되며, John에 저장된 데이터(프로퍼티) 역시 메모리에서 사라집니다.
가비지 컬렉션 후 최종 메모리 구조는 아래와 같습니다.
⇒ 사실 Reference-counting 알고리즘에 따르면, 함수 내에서 두 객체가 서로를 참조하는 순환 참조는 객체가 여전히 서로를 참조하고 있기 때문에 가비지 컬렉팅되지 않습니다.(= 메모리 누수 발생!) 하지만 이는 Mark-and-Sweep 알고리즘에 의해 보완됩니다. ( 이후 가비지컬렉션 알고리즘 파트에서 더 자세히 설명하겠습니다 :))
family = null;
가비지 컬렉션은 크게 두 가지 알고리즘이 존재합니다.
말 그대로 참조 개수를 카운팅하면서, 참조가 하나도 없으면 가비지로 판단하는 방식입니다. 결국 위에서 설명한 예시들의 동작과정을 의미합니다.
절차
단점
Mark-and-Sweep의 구동과정
아래 예시 코드를 통해 구동 과정을 살펴봅시다!
let x = {
a : {
b : 2 {
}
}
let y = x
x = 1
let z = y.a.b
y='bumsu'
z=null
**Marking**
(중략)
Sweep
흰 색으로 마킹된 객체들을 가비지로 인식하고 메모리를 해제합니다.
Compact
메모리의 파편화가 심해지지 않도록 메모리를 재배치하여 메모리를 확보합니다.