가비지 컬렉션은 프로그램에서 더이상 사용하지 않는 메모리를 자동으로 정리하는 것이다. 이 기능을 가진 언어는 자바, C#, 자바스크립트 등이 있다.
자바스크립트는 눈에 보이지 않는 곳에서 메모리 관리를 수행한다.원시값, 객체, 함수 등 우리가 만드는 모든것은 메모리를 차지한다. 그렇다면 더는 쓸모 없어지게 된 것들은 어떻게 처리가 될까?
자바스크립트는 ‘도달 가능성’이라는 개념을 통해 메모리 관리를 수행한다.
‘도달 가능한’ 값은 쉽게 말해 어떻게든 접근하거나 사용할 수 있는 값을 의미한다. 도달 가능한 값을 메모리에서 삭제되지 않는다.
명백한 이유 없이 삭제 되지 않는 값들 예시
이러한 값들은 루트(root)라고 부른다.
루트가 참조하는 값이나 체이닝으로 루트에서 참조할 수 있는 값은 도달 가능한 값이 된다.
전역변수에 객체가 저장되어있다고 가정해보자. 이 객체의 프로퍼티가 다른 객체를 참조하고 있다면, 프포퍼티가 참조하는 객체는 도달 가능한 값이 된다. 이 객체가 참조하는 다른 모든것들도 도달 가능하다고 여겨진다.
자바스크립트 엔진 내에선 가비지컬렉터가 끊임 없이 동작한다. 가비지 컬렉터는 모든 객체를 모니터링 하고 도달할 수 없는 객체는 삭제한다.
예시
// user엔 객체 참조 값이 저장된다.
let user = {
name = 'John'
}
이 그림에서 화살표는 객체 참조를 나타낸다. 전역 변수 “user”는 {name:”John”}이라는 객체를 참조한다. John의 프로퍼티 “name”은 원시값을 저장하고 있기 때문에 객체안에 표현했다.
user의 값을 다른 값으로 덮어쓰면 참조(화살표)가 사라지게 된다.
user = null;
이제 John은 도달할 수 없는 상태가 되었다. John에 접근할 방법도, John을 참조하는 것도 모두 사라졌다. 가비지 컬렉터는 John에 저장된 데이터를 삭제하고, john을 메모리에서 삭제한다.
연결된 객체 예시
function marry(man, woman) {
woman.husband = man;
man.wife = woman;
return {
father: man,
mother: woman
}
}
let family = marry({
name: "John"
}, {
name: "Ann"
});
함수 marry
(결혼하다)는 매개변수로 받은 두 객체를 서로 참조하게 하면서 '결혼’시키고, 두 객체를 포함하는 새로운 객체를 반환한다.
메모리 구조는 아래와 같이 나타낼 수 있다.
지금은 모든 객체가 도달 가능한 상태이다. 이제 참조 두 개를 지워보면,
delete family.father;
delete family.mother.husband;
삭제한 두 개의 참조 중 하나만 지웠다면, 모든 객체가 여전히 도달 가능한 상태였을 것이다. 하지만 참조 두 개를 지우면 John으로 들어오는 참조(화살표)는 모두 사라져 John은 도달 가능한 상태에서 벗어나게 된다.
외부로 나가는 참조는 도달 가능한 상태에 영향을 주지 않는다. 외부에서 들어오는 참조만이 도달 가능한 상태에 영향을 준다. John은 이제 도달 가능한 상태가 아니기 때문에 메모리에서 제거되고, John에 저장된 데이터(프로퍼티) 역시 메모리에서 사라지게 된다.
가비지 컬렉션 후 메모리 구조는 아래와 같이 된다.
Reference
가비지 컬렉션
자바스크립트 가비지 컬렉션 (JavaScript Garbage Collection)
트레이싱 : 한 객체에 flag를 두고 가비지 컬렉션 사이클마다 flag에 표시 후 삭제하는 mark and sweep방법이다. 객체에 in-use flag를 두고, 사이클 마다 메모리 관리자가 모든 객체를 추적해서 사용중인지 아닌지를 표시(mark)한다. 그후 표시되지 않은 객체를 삭제(sweep)하는 단계를 통해 메모리를 해제 한다.
레퍼런스 카운팅 : 한 객체를 참조한느 변수의 수를 추적하는 방법이다. 객체를 참조하는 변수는 처음에는 특정 메모리에 대해 레퍼런스가 하나뿐이지만, 변수의 레퍼런스가 복사될 때마다 레퍼런스 카운트가 늘어난다. 객체를 참조하고 있던 변수의 값이 바뀌거나, 변수 스코프를 벗어나면 레퍼런스 카운트는 줄어든다. 레퍼런스 카운트가 0이 되면 그 객체와 관련한 메모리는 비울 수 있다. 레퍼런스 카운드가 0이된다는 말은 아무도 그 객체에 대한 레퍼런스를 가지고 있지 않다는 말과 같다.