클로저는 여러 함수형 프로그래밍 언어에 등장하는 보편적인 특성이다. 클로저가 뭔가요? 하고 물어 본다면 개인적인 결론은 가비지 컬렉팅으로 인해 실행컨텍스트가 종료된 외부함수의 변수를 참조하는 함수
라고 하겠다.
하지만 이런 정의를 먼저 보고 이해를 하려고 하니 개인적으로 클로저의 개념이 받아들이기 힘들었었다. 아래의 코드를 보겠다.
var outer = function(){
var a = 1;
var inner = function(){
console.log(++a);
}
inner()
}
outer()
위의 코드에 대해 설명을 해보겠다.
outer함수에는 a식별자의 변수가 선언되어있고 1이란 값을 할당 받았다. 그리고 outer함수의 내장함수인 inner함수에서는 a라는 식별자가 선언되어 있지 않은데 a값을 핸들링하려하는 상황이다.
가능한 이유는 outer의 내장함수인 inner함수가 실행 될 때 a식별자에 대한 정보가 inner컨텍스트의 environmentRecord에 값을 찾지 못하지만 outerEnvironmentReference에서 상위 컨텍스트인 outer의 lexical환경을 조회(스코프 체이닝)해 a값에 접근 할 수 있습니다.
outer의 실행 컨텍스트가 종료가 되는 시점에서 식별자 정보인 a, inner에 대한 참조를 지우게 되지만 내부함수 inner가 계속해서 a식별자를 조회하니 a라는 식별자 정보는 가비지 컬렉팅 대상에서 제외되는 것 입니다.
결론은 가비지 컬렉팅으로 인해 실행컨텍스트가 종료된 외부함수의 변수를 참조하는 함수
에 대한 내용이 이제는 이해가 갈 것 이라 생각합니다.
클로저를 사용시 메모리 누수의 위험을 조심해야하고 더 나아가 지양해야한다고 주장하는 사람도 있습니다.
하지만 메모리 누수는 개발자가 의도하지 않았지만 가비지 컬렉팅 대상에서 제외 되는 경우입니다. 이러한 메모리 소모는 클로저의 하나의 특성일 뿐입니다. 즉, 개발자가 의도적으로 가비지 컬렉팅 대상에서 제외시켜 설계한 것을 메모리 누수라고 볼 수 없습니다.
결론적으로 발생시킨 클로저가 더이상 필요성이 사라질 때 더이상 메모리를 소모하지 않도록 하면됩니다.
메모리를 소모하지 않게 하기 위해선 참조 카운트를 0으로 만들어 가비지 컬렉팅 대상에 포함시켜야합니다.
참조 카운트를 0으로 만드는 방법은 식별자에 참조형이 아닌 기본형데이터(null, undefined)를 할당해 주면 됩니다.
var outer = function(){
var a = 1;
var inner = function(){
return ++a
}
return inner
}
console.log(outer())
outer = null
위와 같이 outer에 null기본형 데이터를 할당함으로 outer식별자의 inner함수 참조를 끊었습니다.