자바스크립트의 메모리 관리
C언어 같은 저수준 언어에서는 개발자가 메모리를 원하는 시점에 할당하고 또 반환할 수 있다. 하지만 이 방식에는 실수가 존재할 경우 치명적인 문제가 발생하기 때문에 메모리를 잘 관리하는 것은 C언어 같은 저수준 언어 개발자들의 실력과도 관계있다고 생각된다. 반면에 JS는 JS를 사용하지 않는 개발자도 가비지 컬렉터가 존재한다는 것을 알고 있다. 가비지 컬렉터는 메모리 관리를 개발자가 아닌 언어 차원에서 관리해 개발자는 비즈니스 로직에 집중할 수 있도록 도와준다. 하지만 모든 CS 분야가 그렇듯 은 총알은 존재하지 않으며 항상 적절한 trade-off를 감수해야만 한다. 가비지 컬렉션은 치명적인 결과를 낳는 메모리 누수를 막지만, 누수될 메모리를 항상 추적하고 제거하는 등 컴퓨터 연산 비용을 사용하기 때문에 저수준 언어에 비해 성능이 떨어지거나 특정 시점(G.C가 수행될 경우)에 일시적으로 CPU utilization이 증가하는 경향을 보여주게 된다. 또 G.C를 너무 믿어 Javascript, Java 같은 언어에서는 메모리 관리에 대해 고민할 필요가 없다는 잘못된 인상을 줄 수 있다.
메모리의 생존 주기
- 필요할 때 할당
- 사용
- 필요 없어지면 해제
어떤 언어에서든 메모리의 생존 주기는 비슷하다고 할 수 있다. 필요할 때 생성하고, 사용한다. 사용이 끝난 메모리를 다시 반환된다. G.C는 사용이 끝난(or 더 이상 필요하지 않은) 메모리를 제거하기 위한 의사결정은 다음과 같이 결정한다. 이 과정에 참조는 개발자가 할당된 메모리를 접근할 수 있는 입구를 의미하며, 입구가 없다면 개발자는 해당 메모리에 직접 접근할 방법이 없기 때문에 G.C의 대상이 된다.
Reference-counting G.C
Reference-counting(이하, 참조-세기) 알고리즘은 자신을 참조하는 대상들을 Counting 하고 더 이상 자신을 참조하는 곳이 없다면, 즉 Counting이 0인 경우 더 이상 나를 사용할 수 없다고 판단해 반환하는 알고리즘이다. 하지만 이경우 순환 참조($ A \leftrightarrow B $)가 발생할 경우 메모리 누수가 발생하는데, 개발자가 $ A $와 $ B $의 제어권을 잃었지만 메모리 상에서 서로는 서로를 참조하고 있기 때문에 참조-세기 알고리즘의 대상에서 제외된다.
Mark-and-sweep G.C
Mark-and-sweep G.C(이하, 표시하고-쓸기)는 참조-세기의 반례를 해결할 수 있는 알고리즘으로 최신 브라우저는 대부분 이 알고리즘의 기반의 개선된 알고리즘을 사용한다. '닿을 수 없는 오브젝트'는 '참조되지 않은 오브젝트'와 의미가 비슷하지만 참조-세기에서 살펴봤듯이 '참조되지 않은 오브젝트'가 '닿을 수 없는 오브젝트'는 제어권을 잃은 순환 관계를 가지는 오브젝트라는 문제가 존재한다. 이 알고리즘에서는 $ roots $라는 오브젝트의 집합을 가지고 있고 가비지 컬렉터는 이 $ roots $부터 시작해 탐색을 수행한다. 탐색 범위에 포함된 모든 오브젝트는 '닿을 수 있는 오브젝트'에 해당되고 그 외에 오브젝트는 모두 '참조될 수 없는 오브젝트'에 속하게 된다. 잘 생각해보면 참조-세기 알고리즘에서 발생한 순환 관계는 참조될 수 없기 때문에 G.C에 대상이 된다.
참고 사이트
https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management
'메모' 카테고리의 다른 글
Node.js 플랫폼 (0) | 2022.02.04 |
---|---|
Type<Challenge[]> #Easy (0) | 2022.02.04 |
Typescript로 구현한 Linked list (0) | 2022.02.01 |
Generator (0) | 2022.01.01 |
Iteration protocol (0) | 2021.12.31 |