가비지 컬렉션

Bruce·2022년 1월 16일

프론트엔드 코어

목록 보기
30/31

C언어 같은 Low level 언어에서는 개발자가 직접 메모리 할당을 결정/해제 한다.
그러나 High level 언어인 자바스크립트에서는 할당된 메모리를 추적하여 해당 메모리가 더 이상 필요가 없는지를 판단하여 Garbage Collection이 해제를 한다. 그러나 이러한 판단은 비결정적인 문제이므로 모든 상황에서 가비지 컬렉션이 작동되지 않는다. 결론적으로 자바스크립트의 가비지 컬렉션에 대한 잘못된 개념은 혼란을 야기 시킬 수 있고, 시스템적으로 큰 낭비를 가져올 수 있다.
자바스크립트 개발자는 해당 메모리 할당을 명시적으로 해제 해줘야한다.

자바스크립트 가비지 컬렉션의 핵심 개념은 참조이다.

참조하지 않는다일때 가비지 컬렉션이 동작하는데, 개발자는 이 판단을 도와줄 필요가 있다. 판단하는 조건 두가지를 알아보았다.

  1. 참조 세기(Reference-counting Garbage Collection)
    참조 세기 알고리즘은 어떤 다른 객체에서도 참조하지 않는 객체를 더 이상 사용하지 않는 메모리로 판단하고 가비지 컬렉션을 수행한다.
    하지만 서로 다른 객체가 서로를 순환하게 참조하면 가비지 컬렉션은 수행되지 않는다. 이를 "순환 참조"라고 한다.

  2. 표시하고 쓸기(Mark-and-Sweep Garbage Collection)
    표시하고 쓸기 알고리즘은 더 이상 접근할 수 없는 객체(더 이상 접근할 수 없음 -> 더 이상 참조도 할 수 없음)를 더 이상 필요하지 않은 메모리로 판단하고 가비지 컬렉션을 수행한다.
    표시하고 쓸기 알고리즘은 roots라는 집합을 갖고 있고, 이 roots로부터 참조하고있는 객체와 그 객체를 참조하고 있는 객체들을 순환하면서 메모리 할당은 되어 있지만, 더 이상 접근할수 없는 객체들을 판단하여 가비지 컬렉션을 수행한다.
    참조 세기는 참조를 기준으로 판단하기 때문에 문제가 된다.
    보통 함수는 생명 주기가 끝나면 해당 함수 안의 변수들의 메모리 할당도 해제된다. 그러나 클로저 같이 생명주기가 끝난 함수에서 스코프 체인을 타고 올라갔을때, 서로를 순환 참조하고 있는 변수가 있을 경우 할당된 메모리가 여전히 존재하기 때문에 가비지 컬렉션이 실행이 안된다.
    참조 세기와 다르게 표시하고 쓸기 알고리즘은 더 이상 접근할 수없는 객체를 기준으로 판단하기 때문에 해당 케이스 같은 경우에도 가비지 컬렉션이 수행될 수 있다.

    function f(){
      var x = {};
      var y = {};
      x.a = y;         // x는 y를 참조한다.
      y.a = x;         // y는 x를 참조한다.
    
      return function(){
        console.log('it works');
      }
    }
    
    const a = f();
    a();

    순환 참조를 하고 있더라도, 해당 알고리즘이 더 이상 접근할 수없는 객체라고 판별하면, 메모리 할당을 해제한다.
    때문에 현재까지도 대부분의 브라우저에서 채택하고 있는 알고리즘이라고 한다.
    하지만 메모리 누수가 생길 여지는 다분하고, 개발자가 명시적/직접적으로 가비지 컬렉션을 수행할 수는 없다는 한계가 있다.



두 알고리즘의 차이점을 다시 정리 하자면

참조 세기: 더 이상 참조할 수 없음 -> 참조를 할 수 있지만, 접근을 안했을 뿐 접근이 가능하다.
표시하고 쓸기: 더 이상 접근할 수 없음 -> 접근이 불가능하면 참조도 할 수 없음.

profile
Figure it out yourself

0개의 댓글