소프트웨어/JavaScript • Dhtml

IE Memory Leaks

falconer 2007. 5. 31. 00:53
IE의 메모리 릭에 관한 글입니다. 번역한 거라서 그런지 좀 덜 매끄러운 부분이 있네요.

엄밀히 말해서 JavaScript와 JScript는 다른 언어입니다. JScript가 JavaScript 버전에 대응하기는하나 다른 언어이기 때문에 허용하는 것과 그렇지 않은 것, 그리고 가비지 컬렉터와 DOM을 다루는 방법 등이 다릅니다.

JavaScript를 다룸에 있어서 서로 다르다는 사실을 알고 작성하셔야 나중에 "분명히 되야하는데 안되는" 일이 발생해도 당황하지 않을 수 있습니다. JScript에서는 되는게 JavaScript에서는 안될 수도 있으며 반대로 JavaScript에서는 되는 것이 JScript에서는 안될 수도 있습니다. 인코딩, 쉼표 등 이런 문제가 될만한 소재는 매우 다양합니다.

아래에 소개해드리는 글도 JScript가 DOM과 결합할 때 메모리 릭이 있다는 글입니다. 글 중간쯤에 쓴 것과 마찬가지로 옛날에는 별 문제가 없었을지 모르지만 최근의 Ajax 처럼 DOM을 많이 다루게 되는 경우라면 메모리의 누적이 심각한 오류를 불러올 수도 있습니다. 이 외에도 IE의 버그에 관련된 여러가지 팁들이 있는데 차차 작성 혹은 번역해서 올릴 생각입니다.

아... 잠깐 광고. 드디어 팁 갯수가 90개가 되었네요. ^^
.
.
.
.

이 문서는 원본글 작성자인 Douglas Crockford 씨의 동의를 얻어 번역한 글입니다.
_____________________________________________________________________
시스템이 메모리 관리를 올바르게 하지 못한다면 그것을 메모리 릭이라 부른다. 메모리 릭은 일종의 버그이다. 증상으로는 퍼포먼스를 저하시키거나 오류가 발생하는 것 등이 있다.

Microsoft 사의 인터넷 익스플로러에는 많은 종류의 메모리 릭이 내재하고 있는데, 그 중에서 가장 악질은 JScript 와 연동할 때 발생하는 것이다. DOM 객체가 JavaScript 객체(이벤트 핸들링 함수같은)의 레퍼런스를 포함하고, JavaScript 객체가 해당 DOM 객체에 대한 레퍼런스를 포함할 때, 순환구조가 형성된다. 이것 자체로는 문제가 되지 않는다. DOM 객체와 이벤트 핸들러에 대한 다른 참조가 없을 때, 가비지 컬렉터garbage collector (자 동 리소스 관리자)는 그들을 교정하고 사용되었던 메모리 공간을 재할당이 가능하도록 한다. JavaScript의 가비지 컬렉터는 순환에 대해 잘 이해하기 때문에 그것으로 인한 혼란이 없다. 하지만, 안타깝게도 IE의 DOM은 JScript가 관리한다. JScript의 메모리 관리자는 순환에 대해 잘 이해하지 못하기 때문에 매우 많은 혼란을 겪는다. 그 결과, 순환이 발생할 때, 메모리 교정이 일어나지 않으며, 교정되지 않은 메모리를 가리켜 누수되었다leaked고 한다. 시간이 흐르면, 이런 누수현상이 메모리 자원부족memory starvation을 유발한다. 사용된 셀이 메모리를 가득 채우면 브라우저는 자원부족으로 죽어버릴 것이다.

위에서 언급한 현상을 시연해 볼 수 있다. 첫번째 프로그램인 queuetest1에 서 10000개의 DOM 엘리먼트(span)를 만들고 동시에 최근 10개를 제외한 나머지를 전부 삭제할 것이다. 프로그램을 실행할 때, 윈도우즈의 작업관리자의 성능탭을 이용하면 페이지 파일(PF = Page File) 사용량이 항상 일정한지 볼 수 있다. PF 사용량이 변한다면 이는 메모리 할당이 비효율적이라는 것을 의미한다.
다음으로 두번째 프로그램인 queuetest2를 실행해보자. queuetest1과 똑같은 동작을 하지만 각 엘리먼트에 click 핸들러를 추가했다. 모질라와 오페라에서는 PF 사용량이 거의 일정한 반면에 IE에서는 메모리 누수로 초당 1MB 정도의 비율로 사용량이 점점 증가하는 것을 알 수 있다. 종종 이러한 누수현상은 모른채 지나쳤다. 하지만 Ajax 기술이 더 유명해짐에 따라 각 페이지에서 더 오래 머무르게 되고 더 많은 변화와 실패가 일반적이게 되었다.

IE가 자기일이나 순환 교정을 제대로 못하기 때문에 그 일은 고스란히 우리 몫이 되었다. 명시적으로 순환을 해제한다면 IE도 메모리를 교정할 수 있다. Microsoft에 따르면, closures가 메모리 누수의 원인이 된다고 한다. 이건 물론 매우 틀린 말이지만, Microsoft가 자신들의 버그에 대해서 개발자들에게 아주 나쁜 조언을 하는 결과를 가져왔다. 순환구조는 DOM 쪽에서 끊는 것이 더 쉽다. 사실상 JScript 쪽에서 순환구조를 끊기란 불가능하다.

엘리먼트를 다룰 때는, 순환구조를 끊기 전에 반드시 모든 이벤트 핸들러를 null로 만들어야 한다. 모든 이벤트 핸들러 프로퍼티에 null값을 할당하기만 하면 된다. 이런 기능을 필요할 때마다 혹은 purge와 같은 일반적인 함수로 만들어 실행할 수도 있다.

purge 함수는 DOM 엘리먼트를 인자로 받는다. 엘리먼트의 어트리뷰트를 루프돌면서, 함수를 찾으면 null 로 만들어 순환구조를 끊고 메모리가 교정될 수 있도록 한다. 함수는 또한 모든 하위 엘리먼트들에도 같은 작용을 해서 순환구조가 잘 제거되도록 한다. purge 함수는 모질라와 오페라에는 아무런 해가 없으며 IE에만 작용한다. purge 함수는 엘리먼트가 removeChild 메소드나 innerHTML 속성으로 삭제되기 전에 호출되어야 한다.

function purge(d) {
  var a = d.attributes, i, l, n;
    if (a) {
      l = a.length;
      for (i = 0; i < l; i += 1) {
        n = a[i].name;
        if (typeof d[n] === 'function') {
        d[n] = null;
      }
    }
  }
  a = d.childNodes;
  if (a) {
    l = a.length;
    for (i = 0; i < l; i += 1) {
      purge(d.childNodes[i]);
    }
  }
}

끝으로 세번째 프로그램 queuetest3를 실행해보자. 여기서는 DOM 엘리먼트를 삭제하기 전에 purge 함수를 호출했다.

queuetest1 : http://www.crockford.com/javascript/memory/queuetest1.html
queuetest2 : http://www.crockford.com/javascript/memory/queuetest2.html
queuetest3 : http://www.crockford.com/javascript/memory/queuetest3.html

덧글 1 :
IE에서 사용되고 있는 것은 JavaScript 를 본따 만든 JScript 입니다. MS에서 만든 JavaScript 호환 언어입니다. 대부분의 경우에는 큰 고민없이 그냥 사용하셔도 되지만 일부 문제 혹은 특성이 있으니 그 부분만 주의하시면 됩니다.

http://en.wikipedia.org/wiki/JScript

덧글 2 :
이 글에서의 순환은....
메모리 관리가 잘 안되는 JScript 와 DOM 간의 순환구조를 말합니다. JScript 함수가 DOM의 이벤트 핸들러로서 참조되고 JScript 에서는 함수 내부에 이 DOM 객체에 대한 참조를 가지고 있는 겁니다. 자세한 것은 위 링크에서 queuetest2 번의 onclick 핸들러의 함수 코드를 한번 보세요. DOM 객체를 내부에 참조하고 있음을 알 수 있습니다.



출처  : 행복한고니