블로그 내 검색

2012. 7. 30.

IE 이벤트 모델의 메모리 누수

표준 스크립트 엔진과 다르게 마이크로소프트의 JScript 엔진은 클로저(Closure)에 대해 제대로 처리해주지 못하기에 메모리 Leak이 발생하는건 잘 알려져 있습니다.

JScript가 자바스크립트 객체와 DOM 간의 순환 참조 (circular reference) 가 발생할 때, 가비지 컬렉팅을 제대로 수행해주지 못하기 때문입니다.

circular reference
// 순환 참조 코드
// 정상적인 엔진은 이것을 Closure로 이해하며 엘리먼트가 
// 참조를 잃을 경우 카비지 컬렉팅 된다.
// 그러나 JScript 는 순환 참조로 인식하여 
// 서로 참조를 기억하고 컬렉팅되지 않는다.
var actionButton = document.createElement("button");
actionButton.innerHTML = "Click Me";

var pullhandler = function(e) {
    // Element가 Handler에서 참조. Closure.
    actionButton.innerHTML = "Pushed"; 
    pullContent();
};
// Handler를 Element 가 참조.
actionButton.onclick = pullhandler; 

document.body.appendChild(actionButton);

DOM 객체가 이벤트 핸들링 함수같은 자바스크립트 객체를 참조하고, 그 자바스크립트 객체는 DOM 객체를 참조할 때, 클로저가 형성됩니다.

클로저를 잘 이해하는 표준 스크립트 엔진은 이를 잘 처리하여 DOM객체나 자바스크립트 객체로 향하는 다른 참조가 없을 경우 가비지 컬렉팅이 되며 메모리를 해제합니다.

보통 innerHTML 등으로 컨텐트가 없어질 때, removeChild 등으로 엘리먼트가 삭제될 때, 페이지 언로드시 등등에서 발생하지요.

그러나 IE의 JScript의 경우 이러한 가비지 컬렉팅 사이클을 잘못 처리합니다. 사용된 순환 참조가 많을수록 암세포처럼 메모리를 잠식하며 결국엔 브라우저는 죽습니다.

제일 쉬운 해결 방법은 어떤 이유로 객체가 제거될 때, 명시적으로 null 을 주는 것입니다.

try-catch-finally 구문으로 줄 수도 있고, purge 함수를 구현하여 명시적인 해지를 시킬 수도 있습니다.

순환 참조에 대해서는 다음 자료를 참고하면 좋을 것 같습니다.
http://www.slideshare.net/tifftiff/memory-leaks-in-ie (PT, 영문, 추천)

최근 IE8에 와서는 문제가 수정되었다고 하네요.
(IE7 이하는 아직 문제가 많기에 하위호환이 필요한 경우는 고려가 필요합니다.)