• 자바스크립트 메모리 관리 [가비지 컬렉션] :: 마이구미
    Javascript 2016. 7. 12. 21:56
    반응형

    이번 글은 자바스크립트의 메모리 관리에 대해 알아볼 것이다.

    C를 사용해 봤다면 malloc() 과 free() 사용했을 것이다.

    예를 들어 무언가를 생성하고 메모리를 할당하고 필요없어지면 메모리에서 없애버리기 위해 사용한다.


    이렇게 C나 C++은 메모리를 직접 할당하고 해제하여야한다.

    그에 반해 자바는 GC라는 녀석이 자동으로 메모리를 관리해주고 있다.

    이 GC가 가비지 콜렉션(Garbage Collection)이다. 이것은 C와 JAVA의 큰 차이 중 하나이다.


    자바스크립트 또한 자바처럼 GC를 통해 메모리를 관리한다.

    다시 한번 말하자면 C나 C++은 소스를 통해 메모리를 직접 할당하고 직접 해제하여야한다.

    그에 반해 자바나 자바스크립트와 같은 고급 언어들은 GC라는 녀석이 알아서 필요없으면 메모리를 해제하여 관리를 해준다.


    즉, 가비지 콜렉터란 메모리 할당을 추적하고 할당된 메모리가 더 이상 필요 없어졌을 때 해제하는 작업을 한다. 


    자바스크립트의 GC는 익스플로러 6,7까지 Reference-counting 알고리즘을 사용하였고,

    이후 Mark-and-sweep 알고리즘을 사용하였다.


    먼저 Reference-counting 알고리즘을 알아보자.


    이 알고리즘은 "더 이상 필요없는 오브젝트"를 "어떤 다른 오브젝트도 참조하지 않는 오브젝트"라고 정의한다. 어떤 오브젝트를 참조하는 다른 오브젝트가 하나도 없다면 그 오브젝트에 대해 가비지 콜렉션을 수행한다.


    예제를 보자.


    var obj = { a: { b:2 } }


    보시다시피 { a: { b:2 } } 객체와 { b:2 } 객체 2개를 생성했다.
    { a: { b:2 } } 객체는 obj라는 변수에 할당하였고, { b:2 } 객체는 속성으로 참조되었다.
    여기서 위 정의와 같이 GC가 수행될 메모리는 존재하지 않는다.

    var obj2 = obj;


    변수 obj2 에 obj를 할당하였다.

    현재 { a: { b:2 } } 객체를 참조하는 변수는 obj, obj2가 되었다.


    var obj = 1;


    변수 obj에 1을 할당하여도 { a: { b:2 } } 객체를 참조하는 변수는 obj2가 있기에,

    여기서도 또한 GC가 수행될 메모리는 존재하지 않는다.


    var obj3 = obj2.a;


    변수 obj3에 { b:2 } 객체를 할당하였다.

    obj2.a를 참조하는 변수는 obj2와 obj3가 되었다.


    var obj2 = 1;


    변수 obj2에 1을 할당하여 유일하게 obj의 있던 객체를 참조하는 변수는 사라졌다.

    그렇다면 GC가 수행되어야한다.

    하지만 obj 객체에 있던 a 속성이 변수 obj3에 의해 참조되고 있으므로 GC는 수행되지 않는다.


    var obj3 = 1;


    변수 obj3 마저 1을 할당함으로써 이제 obj 객체를 참조하는 것이 없으므로 GC가 수행되어진다.


    위와 같은 설명으로 보면 아무 문제 없다.

    근데 왜 Reference-counting에서 Mark-and-sweep로 개선되었을까?

    그 이유는 다음과 같은 순환 참조의 경우이다.


    function f() {

    var o = {};

    var o2 = {};

    o.a = o2; // o는 o2를 참조한다.

    o2.a = o; // o2는 o를 참조한다.

    return "azerty";

    }

    f();


    위와 같은 경우 f() 함수가 호출되어지면 o, o2 객체는 아무 의미가 없어지기 때문에

    GC가 수행되어 메모리를 해제해줘야한다.

    하지만 서로 참조를 하고 있는 상황이기 때문에 GC가 수행되지 않는 문제점이 발생했다.


    그리하여 Mark-and-sweep 알고리즘으로 개선되었다.


    이 알고리즘은 "더 이상 필요없는 오브젝트"를 "닿을 수 없는 오브젝트"로 정의한다.

    이 알고리즘은 roots 라는 오브젝트의 집합을 가지고 있다(자바스크립트에서는 전역 변수들을 의미한다). 주기적으로 가비지 콜렉터는 roots로 부터 시작하여 roots가 참조하는 오브젝트들, roots가 참조하는 오브젝트가 참조하는 오브젝트들... 을 닿을 수 있는 오브젝트라고 표시한다. 그리고 닿을 수 있는 오브젝트가 아닌 닿을 수 없는 오브젝트에 대해 가비지 콜렉션을 수행한다.

    정의대로 순환 참조가 일어났다고해도 roots로 인해 오브젝트가 닿을 수 없다면 GC가 수행된다.

    이로써 순환 참조의 문제는 발생되지 않는다.


    더욱 더 깊은 내용이 많지만 더 깊게는 잘 모르겠다..

    다음에 기회가 된다면 정리 후 글을 작성하겠다.


    관련 자료

    https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management



    반응형

    댓글

Designed by Tistory.