
자바스크립트는 메모리 관리를 자동으로 해줍니다. 자바스크립트 엔진이 사용되지 않는 메모리를 자동으로 해제하고 가비지 컬렉팅(Garbage Collecting)하여 메모리 낭비를 없애주죠. 개발자가 함수나 객체를 선언하고 나서 함수 생명주기가 끝나면 자바스크립트의 가비지 컬렉터가 알고리즘에 따라 가비지 컬렉팅을 수행합니다.
이름에서부터 의미를 유추할 수 있겠지만 레퍼런스 = 참조를 기준으로 가비지 컬렉팅을 하는 방식의 알고리즘입니다.
자신을 참조하고있는 객체가 없는 객체는 가비지 컬렉터가 Sweep합니다.
레퍼런스 카운트의 문제점은 순환 참조가 일어나는 구조의 객체가 있을 때 Sweep을 하지 못한다는 것입니다.

가비지 컬렉터는 가비지 컬렉터 루트(GC Root)로부터 순차적으로 연결된 객체들을 카운트하지만 참조로 연결되어있지 않은 객체들만 가비지 컬렉팅을 수행하는데, 순환 참조중인 객체들은 GC 루트와 연결되어있지 않지만 참조되어있는 상태라 가비지 컬렉팅을 수행하지 않습니다. 가비지 컬렉팅이 되지 않으면 메모리 누수가 발생하겠죠.
레퍼런스 카운트의 문제점을 개선하기 위해서 나온 것이 Mark and Sweep입니다.
GC 루트와 연결되어 있지 않기 때문에 Sweep을 정상적으로 수행합니다.
현재 자바스크립트의 가비지 컬렉션 알고리즘도 마크 앤 스윕으로 동작합니다.
객체에 표시를 남긴 뒤, 표시가 남지 않은 객체는 가비지 컬렉팅을 수행합니다. 먼저 출발점인 가비지 컬렉션 루트(GC 루트)는 특별한 객체입니다. 가비지 컬렉터가 관리하는 특별한 객체로써, 외부에서 접근할 수 있도록 만드는 스타팅 포인트 역할을 합니다. 프로그램이 돌면서 메모리에 할당될 때 GC 루트와 간접적으로 연결된 상태로 할당됩니다. 예시로는 Active Thread가 GC 루트가 될 수 있습니다.
가비지 컬렉션을 실행해야 되는 시간이 되면 GC 루트로부터 검사가 시작됩니다. 순차적으로 연결된 객체의 참조를 타고 확인하면서 가비지 컬렉터가 접근했던 객체에는 표시를 합니다. 이걸 Mark 단계라고 합니다.
Mark가 되지 않은 객체에는 접근이 불가하고, 사용되지 않는 객체라 판단하여 메모리를 해제합니다. 예를 들어 어떤 함수에서 객체를 생성해서 메모리를 할당 받은 후 함수의 실행이 끝나서 메모리에서 해제되었다면 이 함수에서 생성된 객체는 참조하는 모체가 사라진 것이라서 GC 루트로부터 끊어지게 됩니다. 그래서 GC 루트로부터 수행되는 Mark 과정에서 마킹이 되지 않기 때문에 Sweep 단계에 메모리에서 해제됩니다.
이러한 이유로 인해 자바스크립트나 리액트에서 코드를 짤 때 전역 변수가 메모리 누수를 일으키는 원인인 경우가 많습니다. 함수는 메모리 할당이 함수의 생명주기가 끝나면 같이 해제가 되지만, 전역 변수는 GC 루트와 가까운 곳에 직접 생성이 되기 때문에 해제를 직접 하지 않으면 GC 루트에서 항상 접근 가능한 상태로 남아있게 되는 터라 계속해서 메모리를 차지하고 있게 되는 것이죠. 이번 시간에는 가비지 컬렉팅과 알고리즘에 대해서 알아보았습니다.