본문 바로가기

모던 자바스크립트

4.3 가비지 컬렉션

📢 메모리 관리 방법 중 하나. 객체가 생성되었을 때 자동으로 메모리를 할당하고 쓸모 없어졌을 때 자동으로 해제한다

 

 

가비지 컬렉션 기준

◾️ 도달 가능성(reachability)라는 개념을 사용해 메모리 관리를 수행한다. 

◾️ 어떻게든 접근하거나 사용할 수 있는 값. 도달 가능한 값은 메모리에서 삭제되지 않는다. 

◾️ 루트(root) 값의 예시 (생성 되었을 때부터 도달 가능한 값)

   1. 현재 함수의 지역 변수와 매개변수

   2. 중첩 함수의 체인에 있는 함수에서 사용되는 변수와 매개변수

   3. 전역 변수

◾️ 루트가 참조하는 값이나 체이닝으로 루트에서 참조할 수 있는 값은 도달 가능한 값이 된다. 

◾️ 자바스크립트 엔진 내에선 가비지 컬렉터가 끊임없이 동작한다. 모든 객체를 모니터링 하고, 도달 할 수 없는 객체는 삭제한다. 

 

 

예시

◾️ 전역 변수 "user"는 { name: 'suzu' }라는 객체를 참조한다.

◾️ 변수 "user"의 값을 다른 값으로 덮어쓰면 참조가 사라진다. 

◾️ { name: 'suzu' } 객체에 도달 할 수 없는 상태가 되었으므로 가비지 컬렉터는 suzu에 저장된 데이터를 삭제하고, 메모리에서 삭제한다. 

let user = {
   name: 'suzu'
}

user = null;

 

 

두 개의 참조

◾️ 전역 변수 'user'와 'admin'은 같은 객체를 참조하고 있다. 

◾️ 'user'를 다른 값으로 덮어써도 'admin'을 통해 객체에 접근할 수 있기 때문에 객체는 메모리에서 삭제되지 않는다. 

◾️ 'admin' 에도 다른 값을 덮어쓰면 객체는 메모리에서 삭제될 수 있다. 

let user = {
   name: 'suzu'
}

let admin = user;

user = null;

 

 

연결된 객체

◾️ 함수 marry는 매개변수로 받은 두 객체를 서로 참조하게 하고, 두 객체를 포함하는 새로운 객체를 반환한다.

◾️ 모든 객체가 도달 가능한 상태이다. 

function marry(man, woman){
   woman.husband = man;
   man.wife = woman; 
   
   return {
      father: man,
      mother: woman
   }
}

let family = marry(
   { name: 'jun' }, 
   { name: 'suzu'}
);

console.log(family);
// father: { name: 'jun', wife: { name: 'suzu', husband: [Circular] }},
// mother: { name: 'suzu', husband: { name: 'jun', wife: [Circular] }}

◾️ 참조 2개를 지운다. 

delete family.father;
delete family.mother.husband;

◾️ father: { name: 'jun', wife: { name: 'suzu', husband: [Circular] }},
◾️ mother: { name: 'suzu', husband: { name: 'jun', wife: [Circular] }}

◾️ { name: 'jun'} 은 도달 가능한 상태에서 벗어나게 되므로 메모리에서 제거된다.  

◾️ 외부로 나가는 참조는 도달 가능한 상태에 영향을 주지 않는다. 외부로 들어오는 참조만이 도달 가능한 상태에 영향을 준다.

 

 

도달할 수 없는 섬

📢 객체들이 연결되어 섬 같은 구조를 만드는데, 이 섬에 도달할 방법이 없는 경우, 섬을 구성하는 객체 전부가 메모리에서 삭제된다. 

◾️ 'jun'과 'suzu'는 서로를 참조하고 있고, 두 객체 모두 외부에서 들어오는 참조를 갖고 있지만 'family'에 새로운 값을 덮어쓰면 객체와 루트의 연결이 사라지면서 루트 객체를 참조하는 것이 아무것도 없게 된다. 

function marry(man, woman){
   woman.husband = man;
   man.wife = woman; 
   
   return {
      father: man,
      mother: woman
   }
}

let family = marry(
   { name: 'jun' }, 
   { name: 'suzu'}
);

family = null;

 

 

내부 알고리즘

📢 mark-and-sweep : 가비지 컬렉션 기본 알고리즘

 

가비지 컬렉션의 수행 단계

(좌)객체 구조와 도달할 수 없는 섬(우)

◾️ 가비지 컬렉터는 루트(root) 정보를 수집하고 이를 'mark(기억)' 한다. 

루트 mark

◾️ 루트가 참조하고 있는 모든 객체를 방문하고 이것들을 mark한다. 

◾️ mark된 모든 객체에 방문하고 그 객체들이 참조하는 객체도 mark한다. 한번 방문한 객체는 전부 mark하기 때문에

   같은 객체를 다시 방문하는 일은 없다. 

◾️ 루트에서 도달 가능한 모든 객체를 방문할 때까지 위 과정을 반복한다. 

◾️ mark 되지 않은 모든 객체를 메모리에서 삭제한다. 

도달할 수 없는 섬 삭제

 

 

루트에서 페인트를 들이붓는다고 상상하면 이 과정을 이해하기 쉽습니다. 루트를 시작으로 참조를 따라가면서 도달가능한 객체 모두에 페인트가 칠해진다고 생각하면 됩니다. 이때 페인트가 묻지 않은 객체는 메모리에서 삭제됩니다.

 

최적화 기법

generational collection(세대별 수집) 

◾️ 객체를 '새로운 객체'와 '오래된 객체'로 나눈다. 

◾️ 새로운 객체 : 생성 이후 제 역할을 빠르게 수행해 금방 쓸모가 없어지는 객체

◾️ 오래된 객체 : 일정 시간 이상 동안 살아남은 객체

◾️ 비지 컬렉터는 새로운 객체를 공격적으로 메모리에서 제거하고, 오래된 객체는 덜 감시한다. 

 

incremental collection(점진적 수집)

◾️ 방문해야 할 객체가 많을 때 실행 속도가 느려지는 현상을 개선하기 위한 방법

◾️ 가비지 컬렉션을 여러 부분으로 분리한 다음, 각 부분을 별도로 수행한다. 

◾️ 작업을 분리하고, 변경 사항을 추척하는 데 추가 작업이 필요하긴 하지만, 긴 지연을 짧은 지연 여러 개로 분산시킬 수 있다

 

idle-time collection(유휴 시간 수집)

◾️ 가비지 컬렉터는 실행에 주는 영향을 최소화하기 위해 CPU가 유휴 상태일 때에만 가비지 컬렉션을 실행한다. 

 

 

 

📝 요약

가비지 컬렉션은 엔진이 자동으로 수행하므로 개발자는 이를 억지로 실행하거나 막을 수 없습니다.
객체는 도달 가능한 상태일 때 메모리에 남습니다.참조된다고 해서 도달 가능한 것은 아닙니다.
서로 연결된 객체들도 도달 불가능할 수 있습니다.

 



📝 오늘 새롭게 배운 내용 📝

 

✅ 가비지 컬렉터가 하는 일 

✅ 참조는 중요하다

✅ 쓸모없으면 버리자

✅ 어렵다

 

 

 

📌 [JAVASCRIPT_INFO 가비지 컬렉터]

 

가비지 컬렉션

 

ko.javascript.info

📌 [MDN 자바스크립트의 메모리 관리]

 

자바스크립트의 메모리관리

메모리 생존주기는 프로그래밍 언어와 관계없이 비슷하다.

developer.mozilla.org

 

 

 

 

'모던 자바스크립트' 카테고리의 다른 글

4.5 'new' 연산자와 생성자 함수  (0) 2020.08.10
4.4 메서드와 'this'  (0) 2020.08.08
4.2 객체 - 참조에 의한 객체 복사  (0) 2020.08.05
4.1 객체 - 객체  (0) 2020.08.04
모던 JavaScript 정독하기  (0) 2020.08.04