Front-end/JavaScript

JS 동작원리 3편 - 메모리 힙 (Memory Leak, Garbage Collector)

파리외 개발자 2022. 11. 2. 17:36

지금까지 JS가 어떻게 번역되어서 기계에게 전달되는지 알아봤다.

이번에는 코드를 읽는 과정에서 데이터를 메모하여 저장하는 공간에 대해 알아볼 것이다.

 

메모리 힙

힙 자료구조와 Call by value, Call by reference 개념에 대한 학습이 선행되길 추천

코드를 읽는 과정에서 변수 선언을 만나면 해당 데이터를 저장할 공간이 필요하게 된다.

여기서 number와 string변수는 Call by value

human객체는 Call by reference 형식을 가진다.

메모리 힙에는 Call by reference형식의 데이터만이 저장된다.

힙과 스택의 자료구조와 변수 참조 형식에 대해 이해하고 있다면 

왜 두 다른 저장공간을 사용해서 참조 변수만을 힙에 저장하는지 알 수 있을 것이다.

 

메모리 누수 (Memory Leak)

arr는 배열이고 무한 for문으로 배열의 값을 무한으로 추가해본다.

크롬 개발자 콘솔에 실험해보지 않길 바란다. 페이지가 다운된다.

Vsc에서 코드를 실행한 결과 얼마의 시간이 지난 뒤 에러코드가 뜬다.

메모리 힙도 당연하지만 저장공간의 한계가 있고 이 한계를 넘어서는 데이터가 저장되면 메모리 누수가 발생한다.

 

가비지 컬렉션 - Mark & Sweep

당연하게도 한계가 있는 힙 공간에 사용되지 않는 데이터를 제거하지 않고 프로그래밍하다 보면

언젠가는 메모리가 넘치는 상황이 생길 것이다.

이를 위해서 JS에서는 사용하지 않는 데이터를 메모리 힙 공간에서 제거해주는

가비지 컬렉션을 사용하는 데에 Mark and Sweep이라는 알고리즘을 사용한다.

이와 같이 human이라는 객체를 생성한다고 하면 

지금 human객체는 first와 last라는 속성의 데이터를 참조하고 있다.

현재 참조하고 있다는 것을 화살표로 표시하고 있다.

여기서 만약 human객체에 다른 값이 저장된다면 새로운 데이터에 참조를 하게 된다.

(사실상 5는 call by value이기 때문에 mark가 되지는 않는다. 예시일 뿐이다.)

root에서 직접 참조하고 있는 데이터를 mark 하고 남겨두고

화살표가 닿지 않는, 참조되지 않는 데이터를 힙 공간에서 삭제하는 sweep과정을 거친다.

 

메모리 힙을 위한 세 가지 요소

전역 변수

지역변수는 해당 스코프에 해당하는 함수 등이 종료되면 메모리 할당이 종료된다.

하지만 global영역의 전역 변수는 계속해서 참조를 유지하여 메모리 공간을 차지하고 있을 수 있으니

꼭 필요한 경우가 아니라면 지양하도록 한다.

이벤트 리스너

이벤트 리스너는 당연하게도 따로 삭제를 시켜주지 않는 이상 계속해서 활성화되어있다.

리스너를 필수적인 것만 배치하거나 이벤트를 제거해주는 등 리스너 수를 줄이는 것이 

메모리 공간 최적화에 도움이 된다.

setInterval

만약 인터벌 함수가 객체를 참조하게 된다면 해당 객체는 계속해서 메모리 공간에 남아있으므로

필요한 경우에만 유의해서 사용하도록 한다.