가비지 컬렉션..이란 무엇일까요?
말그대로 쓰레기 수집이라는 것이겠죠?
뭐 흔히 안좋은 연애를 많이 하는 사람들은 가비지 컬렉터라고도 불리는 데..
논외인 듯 합니다..쨌든 본론으로 돌아가 가비지 컬렉션이 뭔지 좀 알아보고자 합니다.
javascript 는 눈에 보이지 않는 곳에서 메모리 관리를 수행한다고 합니다.
원시값 객체 함수 등 우리가 만드는 모든 것은 메모리를 차지합니다.
원시값은 (number string undefined boolean null)요래 있는 걸로 압니다.
아 Symbol도 있쥬ㅋ
그렇다면 쓸모 없어지게 된 것들은 JS 엔진이 어떻게 찾아내서 삭제하는지 알아보자고 하네요.
자바스크립트는 도달 가능성(reachability)이라는 개념을 사용해서 메모리 관리를 한다고 합니다. 륏ㅊ어빌리리
'도달 가능한(reachable)' 값은 쉽게 말해 어떻게든 접근하거나 사용할 수 있는 값을 의미합니다. 도달 가능한 값은 메모리에서 삭제되지 않습니다.
무슨 말인지 잘모르겠지만 일단 어떻게든 사용 가능한 값은 가비지가 아니라는 것인가?!
그러니까 루트에서 참조불가능한 값은 가비지라고 ?
let user = {
name: "John"
};
변수 user 는 {name: John} 이라는 객체를 참조하고 있습니다. John 객체로 생략해서 설명하겠습니다.
user = null;
위처럼 코드로 user 의 값이 아예 다른 값으로 덮어쓰이게 된다면?
그렇죠. 이제 user 를 통해 John 객체를 참조할 수 없게 됩니다. 그러면 더이상 John 객체는 사용할 수 없고, 즉 도달 불가능한 상태가 되겠네요. 이 때 js 엔진의 가비지 컬렉터가 이를 감지하고 John이 저장된 메모리를 삭제합니다.
다음 예시를 볼까요?
let user = {
name: "John"
};
let admin = user;
user = null;
이 경우는 어떻게 될까요?
user 변수는 메모리 영역에 John 객체의 메모리주소와 함께 존재합니다. admin 은 이 주소를 복사하여 같은 John 객체를 참조하고 데이터를 공유하고 있겠죠. 이 후 user의 값은 null 로 덮어씌워지게 되었습니다.그러므로 더이상 user 를 통해서 John 객체를 참조할 수 없게 됩니다. John 객체는 가비지메모리 일까요?
아닙니다.
admin 변수는 user 의 값이 복사되어 John 객체의 주소값이 담겨있습니다. 고로 user 의 값이 null 로 덮어씌워진다 한들 admin 에서는 여전히 John 객체에 접근가능하고 이는 도달가능한 값이라는 얘기죠.
그렇다면 얕은 복사가 아닌 깊은 복사라면 user 의 John 은 삭제되겠지??
위 의문을 통해 얕은 복사와 깊은 복사에 대해 좀더 공부했고 해당 게시물을 작성하게 되었습니다. 결론적으로 위 의문에 스스로 답을 할 수 있게 되었죠.
깊은 복사로 예를 들어보겠습니다.
let user = {
name: "John"
};
let admin = { ...user };
user = null;
1 depth 의 객체를 스프레드 연산자를 사용해 deep copy 하는 예시 입니다. 위의 경우 admin 은 user 가 참조하고 있는 john 객체를 복사해서 새로운 메모리 영역에 John 과 똑같은 객체를 복사합니다. 쉽게 말해 user 가 참조하는 John 객체와 admin 이 참조하는 John 객체는 메모리 상 서로 관련이 없는 각각의 데이터 라는 것입니다. 의문이 한가지 더 드는데요..
만약 user 가 2depth 이상의 객체였다면 가비지메모리가 생길까요?
우선 spread operator는 1depth 이 후의 값은 결국 참조를 하게 되는데요. 참조를 한다는 것은 주소값이 있다는 얘긴데 어디다가 주소값을 저장하고 사용하는걸까?
let user = {
name: {
first: "John",
}
};
let admin = { ...user };
user = null;
console.log(admin.name.first); // John
위 코드 실행을 통해 spread operator 는 user 메모리의 John 주소값은 접근하지 않는 다는 사실을 알게 되고 새로운 메모리 영역에 원본 객체의 1depth 값과 원본 객체의 주소값을 저장한다는 것을 알게 되었습니다. 또한 결론 적으로 원본 객체의 주소값을 통해 원본 John 객체에 도달할 수 있기 때문에 가비지메모리는 발생하지 않는거죠.
가족 관계를 나타내는 예시입니다.
function marry(man, woman) {
woman.husband = man;
man.wife = woman;
return {
father: man,
mother: woman
}
}
let family = marry({
name: "John"
}, {
name: "Ann"
});
보시다시피 상당히 복잡한 구조로 되어있네요.
변수 family 는 marry 함수를 통해 John 객체와 Ann객체를 인자로 넣어주었습니다. 그리고 marry 함수에서 두 객체를 매개변수로 받아 연결하고 father 와 mother 프로퍼티에 값을 담아 리턴했습니다.
family: {
father: {
name: "John",
wife: woman, // == { name: "Ann" }
},
mother: {
name: "Ann",
husband: man // == { name: "John" }
}
}
대충 json 으로 표현하자면 이런 느낌일 것 같네요.
delete family.father;
만약 위와 같은 코드로 father 객체에 대한 참조를 끊으면 어떻게 될까요?
family.mother.husband // { name: "John" }
직관적인 참조가 끊어졌지만 mother 객체의 husband 객체를 통해 father 의 프로퍼티에 접근할 수 있고 이는 아직 도달 가능한 상태임을 알 수 있습니다.
그렇다면 아래 경우는 어떻게 될까요?
delete family.mother;
delete family.father.wife;
family 객체 내 mother 객체의 참조를 끊고 father.wife 객체의 참조도 끊어버렸습니다. 이렇게 되면 더이상 { name: "Ann" }에 접근할 방법이 없는 즉, 도달 불가능한 값이 됩니다.이제 가비지 컬렉터는 이를 감지하고 메모리에서 제거하게 됩니다.
family: {
father: {
name: "John",
// wife: woman,
},
// mother: {
// name: "Ann",
// husband: man // == { name: "John" }
// }
}
메모리 구조를 간단하게 JSON으로 표현해봤습니다.
family 전체의 값을 덮어씌우게 된다면 어떻게 될까요?
family = null;
서로 얽혀있는 father와 mother가 포함된 객체에 대한 참조가 끊어지겠죠. 쉽게 말해 더이상 father 와 mother 객체에 접근할 방법이 사라진 것입니다. father 와 mother 두 객체는 서로를 참조하고 있어 한 쪽이 끊어져도 도달이 가능하지만 family 는 두 객체의 상위 객체로 단방향으로 참조한 상태기 때문에 더이상 두 객체에 도달이 불가능해졌습니다. 하나의 값이 아닌 서로 연결되어 있는 뭉치가 떨어져 나간 것이 마치 섬과 같아 도달할 수 없는 섬이라고 부릅니다.
family: null /*{
father: {
name: "John",
wife: woman,
},
mother: {
name: "Ann",
husband: man // == { name: "John" }
}
}*/
메모리 구조는 이런 형태가 되겠네요.
가비지 컬렉션은 'mark-and-sweep' 이라 불리는 알고리즘하에 작동합니다.
간단하게 가비지 컬렉터는 최상위 객체인 root가 참조하는 객체를 marking 합니다.이 후 marking 된 객체가 참조하는 객체도 marking 하고 이 과정을 반복해 결론적으로 root가 도달할 수 있는 모든 객체에 marking합니다. 그리고 marking 되지 않은 객체는 메모리에서 삭제시키는 형태로 동작합니다. 조금 쉽게 생각하면 흔히 마인드맵과 비슷한 형태라고 생각하면 될 것 같네요. 마인드맵 메인 키워드로부터 연결된 것이 아닌 항목을 지우개로 지운다라고 이해하는 건 어떨까요!
JS 엔진은 실행에 영향을 미치지 않고 가비지 컬렉션을 더 빠르게 수행하게하는 기법들이 있다고 합니다.이 외에도 엔진별 다양한 기법과 가비지 컬렉션 알고리즘이 존재한다는 군요. 그에 대한 내용도 언젠간 공부하고 기록하는 날이 오겠죠. 무엇보다 지금 제가 이해하는 선에서 필요한 정보를 얻는 것이 중요하다고 생각합니다. 자바스크립트를 쓰는 개발자로써 자바스크립트와 조금은 친해진 것 같아서 기분이 좋습니다. 말놔도되냐? 아래 자료를 통해 공부했고 이해한 내용을 토대로 저와 같은 초급자분들도 이해할 수 있도록 재해석해보려 했습니다. 누군가에게 도움이 되었으면 하는 마음에 글을 남기고 혹시나 잘못된 정보가 있다면 얼마든지 남겨주세요. 쥔장 연중무휴입니다. 즉시 수정하겠습니다. 오늘도 잘 배우고 갑니다.