이전에 컴퓨터 과학을 CS50(네이버 부스트코스 강의)로 접하면서 C를 사용한 강의를 수강한 적이 있습니다. 이때 C 언어는 malloc() , free()와 같은 함수로 메모리 할당을 해제하는 모습을 보았고 자바스크립트에서는 어떠한 방식으로 메모리를 관리하는지 궁금하여 가비지 컬렉션에 대해 정리를 하게 되었습니다.
garbage collection이란?
메모리 관리 기법 중의 하나로, 프로그램이 동적으로 할당했던 메모리 영역 중에서 필요없게 된 영역을 해제하는 기능입니다.
더보기
메모리 관리
- gif와 같이 컴퓨터는 우리가 작성한 변수, 함수, 객체들을 메모리에 할당한다. 하지만 계속 할당만 해서 메모리가 꽉 차게되면 작업중인 프로그램이 느려지고 결국은 강제종료되는 현상이 일어나게됩니다.
- 가상메모리도 메모리 관리를 위한 기법 중 하나입니다.
- 리스프라는 프로그래밍 언어의 문제를 해결하기 위해 존 매카시가 개발하였습니다.
- C, C++ 등의 프로그래밍 언어는 수동 메모리 관리를 가정하고 설계되었습니다. (malloc() , free())
- Jave, C# 같은 언어들은 처음부터 GC 기법을 염두에 두고 설계되어, 언어 정의에 GC이 포함되어 있습니다. JavaScript도 마찬가지입니다.
메모리 관리의 필요성 (...GC가 필요한 이유)
수동으로 메모리를 관리하는 방식에서 프로그래머가 까먹고 해제하지 못했을 때, 혹은 실수가 발생했을 때 아래와 같은 버그가 발생하게 됩니다.
메모리 누수(memory leak)
- 더 이상 필요하지 않은 메모리가 정리되지 않고 남아있는 버그입니다.
- 메모리 누수의 반복되면 메모리 고갈로 프로그램이 중단될 수 있습니다.
유효하지 않은 포인터 (Dangling Pointer)
- 이미 해제된 메모리에 접근하는 버그입니다.
- 댕글링 포인터인 메모리 접근 시 프로그램이 예측 불가능한 동작을 하게 되는 위험이 있습니다.
이중 해제
- 이미 해제된 메모리를 또 다시 해제하는 버그입니다.
- 이 또한 오류를 일으킬 수 있습니다.
GC의 단점
- 어떤 메모리를 해제할지 결정하는 데 비용이 듭니다. 객체가 필요없어지는 시점을 프로그래머가 미리 알고 있는 경우에도 GC 알고리즘이 메모리 해제 시점을 추적해야 하므로, 이 작업은 오버헤드(처리 시간, 메모리가 소비)가 됩니다.
- GC이 일어나는 타이밍이나 점유 시간을 미리 예측하기 어렵습니다. 때문에 프로그램이 예측 불가능하게 일시적으로 정지할 수 있습니다.
- 할당된 메모리가 해제되는 시점을 알 수 없습니다.
GC Algorithm
대표적인 알고리즘으로 두가지가 있습니다.
참조 횟수 계산 방식(Reference Counting)
- Root Space - 스택 변수, 전역 변수 등 Heap 영역 참조를 담은 변수입니다.
- Heap 영역에 선언된 객체들에 참조 횟수를 기억하고 이 횟수가 0이 되면 해당 객체를 해제하는 방식입니다.
한계점
- 순환 참조의 경우 횟수가 1로 유지되는 문제가 있습니다.
- 대표젹인 예로 도달할 수 없는 섬(Unreachable Island)이 있습니다.
포인터 추적 방식(Mark And Sweep)
- Root와 연결된 객체들(Marked)은 두고 연결이 끊어진 객체들을 지우는 방식(sweep)입니다.
- 객체가 가르키는 영역을 “사용중”으로 표시하고 그 객체가 가리키는 객체도 사용중으로 표시하면 접근 불가능한 메모리를 정리할 수 있습니다.
- 순환 참조의 문제 해결할 수 있습니다.
또 다른 한계점
- 어떤 메모리를 언제 해제할지에 대해 수동으로 결정하는 것이 편할 때가 있습니다.
- 수동으로 메모리를 해제하고 싶다면 객체 메모리가 unreachable 상태로 명시하는 기능이 있어야 합니다..
- 2019년 현재의 JavaScript에서는 명시적으로 또는 프로그래밍 방식으로 가비지 컬렉션을 작동할 수 없습니다.
최적화 기법
- generational collection(세대별 수집)
- incremental collection(점진적 수집)
- idle-time collection(유휴 시간 수집)
JavaScript의 GC
자바스크립트와 같은 고수준 언어들은 자동 메모리 관리 방법을 사용합니다. 가비지 콜렉터의 목적은 메모리 할당을 추적하고 할당된 메모리 블록이 더 이상 필요하지 않게 되었는지를 판단하여 회수하는 것입니다.
- Javascript는 브라우저 엔진 내의 가비지 컬렉터(Garbage Colloector)에서 메모리 관리를 수행합니다.
- GC의 기준은 도달 가능성(Reachability)에 따라서 메모리 관리를 수행합니다..
어떤 알고리즘을 사용할까?
- 인터넷 익스플로러 6, 7 은 DOM 오브젝트에 대해 Reference counting 알고리즘으로 GC를 수행했었습니다. (최신 브라우저는 더 이상 참조 횟수 가비지 콜렉션 방식을 사용하지 않습니다.)
- 현재 엔진은 Mark And Sweep 알고리즘을 사용합니다. (IE, Firefox, Opera, Chrome, Safari)
결론
- 저수준 언어에서는 직접 메모리 할당을 해제하는 작업을 거치지만 고수준 언어는 가비지 컬렉터를 통해 관리합니다.
- 자바스크립트에서는 브라우저, 노드의 V8 엔진의 GC를 통해 메모리를 관리합니다.
- 고수준 언어인 자바스크립트에서는 메모리가 자동으로 관리되기에 이를 억지로 실행하거나 막을 수 없습니다. (수동으로 조작 불가)
- 도달 가능성을 기준으로 유지, 해제하는 (Mark and Sweep) 알고리즘을 사용합니다.
참조
Memory management - JavaScript | MDN
쓰레기 수집 (컴퓨터 과학) - 위키백과, 우리 모두의 백과사전
'프론트엔드' 카테고리의 다른 글
웹 성능 측정 지표(Web Vitals) (0) | 2023.09.05 |
---|---|
브라우저 렌더링 과정 - (리플로우와 리페인트) (0) | 2023.07.03 |
REST API (0) | 2023.05.25 |