클로저와 메모리 누수

메모리 누수란 개발자의 의도와는 달리 데이터의 참조 카운트가 0이 되지 않아 가비지 컬렉팅 대상이 되지 못하는 현상을 의미한다. 하지만 개발자가 의도적으로 참조 카운트를 0으로 만들지 않는 경우에는 메모리 누수라고 하기 어려울 것이다.

클로저는 외부 함수가 종료되었음에도 해당 함수의 지역 변수를 참조하는 내부 함수를 외부로 내놓음으로써 의도적으로 해당 변수의 참조 카운트를 0이 되지 않도록 유지한다.

즉, 클로저를 사용하면서 발생할 수 있는 메모리 문제는 “누수”가 아니라, 잘 관리될 수 있는 이슈란 소리다. 클로저로서 참조하는 지역 변수의 쓸모가 끝난 경우 제대로 정리만 해 주면 되는 것이다. 따라서 클로저는 메모리 누수를 일으키므로 사용을 조심해야 한다거나 지양해야 할 필요는 없다.

클로저의 메모리 관리

클로저에서 사용되는 외부 함수의 지역 변수를 사용하고 나서 참조 카운트를 0으로 만들어 주자. 식별자에 null이나 undefined를 할당해주면 된다.

var outer = (function () {
  var a = 1
  var inner = function () {
    return ++a
  }
  return inner
})()

console.log(outer()) // 2
console.log(outer()) // 3
outer = null         // outer 함수의 inner 함수 참조를 끊음
(function () {
  var a = 0
  var intervalId = null
  var inner = function () {
    if (++a >= 10) {
      clearInterval(intervalId)
      inner = null         // inner 식별자의 참조 끊음
    }
    console.log(a)
  }
  intervalId = setInterval(inner, 1000)
})()

(function () {
  var count = 0
  var button = document.createElement('button')
  button.innerText = 'click'

  var clickHandler = function () {
    console.log(++count, 'times clicked')
    if (count >= 10) {
      button.removeEventListener('click', clickHandler)
      clickHandler = null      // clickHandler 식별자의 참조 끊음
    }
  }
})