Computer >> 컴퓨터 >  >> 프로그래밍 >> JavaScript

자바스크립트에서 Detached DOM 요소가 메모리 누수를 일으키는 이유와 해결 방법

Detached DOM 요소란?

Detached DOM(분리된 DOM) 요소란 DOM 트리에서는 이미 제거되었지만, 자바스크립트의 어떤 변수나 객체가 여전히 해당 요소를 참조하고 있어 가비지 컬렉터(Garbage Collector)가 메모리를 회수하지 못하는 요소를 말합니다. 즉, 요소가 화면에서 사라진 후에도 어딘가에 참조가 남아 있다면 그 요소는 계속 메모리를 차지하게 됩니다.

DOM은 양방향으로 연결된 트리 구조입니다. 따라서 트리 안의 특정 노드 하나만 참조하고 있어도, 그 노드를 포함한 전체 트리가 가비지 컬렉션 대상에서 제외됩니다.

예를 들어, 자바스크립트로 DOM 요소를 생성한 뒤 해당 요소를 DOM에서 제거했지만, 요소를 담고 있던 변수를 삭제하는 것을 잊었다고 가정해 보겠습니다. 이 경우 변수는 특정 DOM 요소뿐 아니라 그 요소가 속한 전체 트리까지 참조하게 되며, 결과적으로 Detached DOM이 발생해 메모리 누수로 이어집니다.

예제

다음 예제에서는 someText 요소가 DOM에서 제거된 후에도 전역 객체 value가 여전히 이를 참조하고 있습니다. 그렇기 때문에 가비지 컬렉터가 이 요소를 정리할 수 없으며, 불필요한 메모리를 계속 소비하게 됩니다. 이것이 바로 메모리 누수가 발생하는 전형적인 시나리오입니다.

<html>
<body>
<script>
    var example = document.createElement("p");
    example.id = "someText";
    document.body.appendChild(example);
    var value = {
     text: document.getElementById('someText')
    };
    function createFun() {
        value.text.innerHTML = "Javascript is not Java";
    }
    createFun();
    function deleteFun() {
        document.body.removeChild(document.getElementById('someText'));
    }
    deleteFun();
</script>
</body>
</html>

위 코드에서 deleteFun()이 실행되면 someText 요소는 화면에서 사라지지만, value.text가 여전히 이 요소를 가리키고 있기 때문에 브라우저는 해당 메모리를 회수할 수 없습니다.

메모리 누수 방지 방법

메모리 누수를 피하는 가장 좋은 방법은 var example처럼 DOM 요소를 담는 변수를 이벤트 리스너(listener) 내부에 선언하여 지역 변수로 만드는 것입니다. 지역 변수는 스코프가 종료되는 순간 참조 경로가 끊기므로, 가비지 컬렉터가 해당 객체의 메모리를 정상적으로 해제할 수 있습니다.

그 외에도 다음과 같은 습관이 도움이 됩니다.

  • DOM에서 요소를 제거하기 전에 해당 요소를 참조하던 변수나 객체의 참조를 먼저 해제합니다(null 할당).
  • 장기간 유지되는 전역 객체나 캐시에 DOM 노드를 저장하지 않습니다.
  • Chrome DevTools의 Memory 탭에서 힙 스냅샷(Heap Snapshot)을 촬영한 뒤 'Detached' 항목을 검색하면, 분리된 DOM 요소가 메모리에 남아 있는지 쉽게 확인할 수 있습니다.

이처럼 참조 관계를 꼼꼼히 관리하면 Detached DOM으로 인한 메모리 누수를 효과적으로 예방할 수 있습니다.