-
[코어 자바스크립트 스터디] 2주차 - 클로저와 GCJavascript 2022. 6. 26. 18:36
1. 발단
let a = 100; console.log(a); // 100
내가 a라는 식별자를 선언하고, 100이라는 값을 할당하게 되면 메모리 변수 영역의 빈 공간을 확보해 이름을 a라고 지정한다. 한편 메모리 데이터 영역에서 100이라는 값을 보관하고 있는 공간이 있는지 확인한다. 없다면 빈 공간에 100이라는 값을 할당한다. 다시 변수 영역 a에서는 100이 저장된 공간의 주소값을 저장한다. 일련의 과정을 마치면 할당된 메모리를 사용할 수 있다.
이미지 출처: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management 같은 방식의 메모리 할당이 무한정 일어난다면 더이상 메모리를 할당할 수 없는 상황이 발생할 것이다. 다행히 자바스크립트과 같은 고수준의 프로그래밍 언어에서는 가비지 컬렉터를 활용하여 메모리 생명주기를 암묵적으로 관리하고 있다. MDN에 따르면 개발자는 대개 할당된 메모리를 읽고 쓰는 2번만을 명시적으로 프로그래밍하게 된다.
그렇다면 Garbage Collection은 어떻게 작동하고 있는 것일까?
2. Garbage Collection
가비지 컬렉션이란 더 이상 사용하지 않는 메모리 할당을 추적하여 메모리 블록이 더 이상 필요하지 않는다고 판단하면 회수하는 과정이다. 여기서 판단의 기준이 무엇이냐?가 문제가 되는데 가비지 컬렉터는 'Reachability(도달 가능성)'를 기준으로 판단한다. 메모리 블록에 있는 값에 접근하거나 사용할 수 있다면 가비지 컬렉터는 해당 블록을 회수하지 않게 되는 것이다.
const cat = { name: 'Happy', age: 8, weight: 5, gender: "M", vaccinated: true } const newCat = {...cat} newCat.owner = "Sung" // Object { name: "Happy", age: 8, weight: 5, gender: "M", vaccinated: true, owner: "sung" }
위 코드를 예시로 한 번 살펴보자.
- 메모리 할당: name, age, weight, gender, vaccinated property를 가진 객체를 cat이라는 식별자에 할당한다
- 메모리 사용: spread operator를 활용해 newCat이라는 식별자에 cat이 참조하고 있는 객체를 '깊은 복사'한다
- newCat에 할당된 객체에 owner property를 추가한다
- 메모리 해제: cat에 관한 참조가 더 이상 일어나지 않으므로 가비지 컬렉터가 해당 메모리 블록을 회수한다
3. 클로저
우선 실제 고양이의 건강 척도와는 전혀 관련이 없는 아래 코드를 살펴보자
function healthCheck(age, weight, bloodPressure, heartRate, vaccinatedYear) { var basicPoint = age * weight; var heartFunction = bloodPressure * heartRate; var vaccinated = vaccinatedYear >= 2021 ? 100 : 0; function detailedCheck() { if (basicPoint > 100) { console.log("This cat needs a diet"); } if (heartFunction > 10000) { console.log("This cat needs more tests"); } if (vaccinated == 0) { console.log("This cat needs vaccination and more tests"); } } return detailedCheck; } const check = healthCheck(13, 10, 100, 100, 2019); console.log(check()); // 실행 결과 // This cat needs a diet // This cat needs vaccination and more tests
check 식별자에 healthCheck 함수의 return값, 즉 detailedCheck 함수를 할당하고 있다. check를 실행하면 healthCheck 함수에 인자로 넘겨주었던 age, weight, bloodPressure, heartRate, vaccinatedYear 값이 반영된 결과가 출력되는 것을 확인할 수 있다. 이 것이 가능한 이유는 가비지 컬렉터가 실행될 함수의 lexical environment를 고려하여 메모리 블록을 회수하기 때문이다.
- healthCheck 함수를 실행하면, basicPoint, heartfunction, vaccinated 식별자가 값을 참조한 메모리 블록들이 할당된다. 동시에 함수의 environmentRecord에 저장된다.
- healthCheck의 실행 컨텍스트가 종료되고 나면, 해당 lexicalEnvironmnet가 모두 가비지 컬렉팅 되어야 하지만, 자바스크립트 엔진은 함수의 environmentRecord에 담긴 세 변수가 detailedCheck 함수를 통해 reachable하다고 판단한다.
- 따라서 basicPoint, heartfunction, vaccinated를 제외한 나머지에 대해서만 CG가 이루어진다.
- check를 실행하면 lexicalEnvironment를 참고해 의도한 결과를 출력할 수 있다.
4. 마무리
클로저와 가비지 컬렉션에 대한 기본 내용을 알게 되면서 엔진에서 '암묵적으로' 실행되는 과정이 정말 많다는 것을 느꼈다. 지금은 구현하는 프로그램의 크기가 크지 않기에 오늘 정리한 내용을 몰라도 큰 문제가 없겠지만, 좀 더 나은 개발자로 성장하기 위해선 꼭 알아야만 하는 내용이라는 확신이 들었다.
한편 GC가 reachable이라고 판단하는 과정이 과연 완벽한지, 그렇지 않다면 자바스크립트엔진에서는 이를 어떻게 보완하고 있는지 궁금해졌다. 추후 공부하는 과정에서 더 깊게 살펴보려고 한다
참고
- https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management#memory_life_cycle
- https://ko.javascript.info/garbage-collection
자바스크립트의 메모리 관리 - JavaScript | MDN
C 언어같은 저수준 언어에서는 메모리 관리를 위해 malloc() 과 free()를 사용합니다. 반면, 자바스크립트는 객체가 생성되었을 때 자동으로 메모리를 할당하고 더 이상 필요하지 않을 때 자동으
developer.mozilla.org
가비지 컬렉션
ko.javascript.info
'Javascript' 카테고리의 다른 글
[코어 자바스크립트 스터디] 1주차 - this와 화살표 함수 (0) 2022.06.16 [코어 자바스크립트 스터디] - 시작 (0) 2022.06.16