DOM 요소가 제거되면 해당 리스너도 메모리에서 제거됩니까?


답변:


307

최신 브라우저

일반 자바 스크립트

제거 된 DOM 요소에 참조가없는 경우 (참조가없는 참조) -요소 자체는 가비지 수집기 및 관련 이벤트 처리기 / 청취자에 의해 선택됩니다.

var a = document.createElement('div');
var b = document.createElement('p');
// Add event listeners to b etc...
a.appendChild(b);
a.removeChild(b);
b = null; 
// A reference to 'b' no longer exists 
// Therefore the element and any event listeners attached to it are removed.

하나; 여전히 상기 요소를 가리키는 참조가 있다면, 요소 및 그 이벤트 리스너는 메모리에 유지된다.

var a = document.createElement('div');
var b = document.createElement('p'); 
// Add event listeners to b etc...
a.appendChild(b);
a.removeChild(b); 
// A reference to 'b' still exists 
// Therefore the element and any associated event listeners are still retained.

jQuery

jQuery의 관련 메소드 (예 :) remove()가 정확히 같은 방식으로 작동 한다고 가정하는 것이 좋습니다 (예를 들어 remove()사용 된 것으로 간주 removeChild()).

그러나 이것은 사실이 아닙니다 . jQuery 라이브러리에는 실제로 DOM에서 제거 할 때 요소와 관련된 모든 데이터 / 이벤트를 자동으로 정리 하는 내부 메소드 (문서화되지 않았으며 이론상 언제든지 변경 될 수 있음)가 있습니다 cleanData() (여기서는이 메소드의 모양입니다 ) (통해이 될. remove(), empty(), html("")등).


이전 브라우저

오래된 브라우저, 특히 오래된 IE 버전은 이벤트 리스너가 연결된 요소에 대한 참조를 유지하기 때문에 메모리 누수 문제가있는 것으로 알려져 있습니다.

레거시 IE 버전 메모리 누수를 해결하는 데 사용되는 원인, 패턴 및 솔루션에 대한 자세한 설명을 보려면 Internet Explorer 누출 패턴 이해 및 해결에 대한이 MSDN 문서 를 읽어보십시오 .

이와 관련된 몇 가지 기사가 더 있습니다.

이 경우 리스너를 수동으로 직접 제거하는 것이 좋은 습관 일 것입니다 (메모리가 애플리케이션에 매우 중요하고 실제로 이러한 브라우저를 대상으로하는 경우에만).


22
요소에 대해 remove () 메소드를 사용할 때 jquery 설명서에 따르면 모든 이벤트 리스너가 메모리에서 제거됩니다. 이것은 selft 요소와 모든 자식 노드에 영향을 미칩니다. 이벤트 리스터를 메모리에 유지하려면 .detach ()를 대신 사용해야합니다. 제거 된 요소가 돔에 다시 삽입 될 때 유용합니다.
Lothre1

1
요소에 자식 elemen이 포함되어 있으면 자식 요소에서 이벤트 목록을 분리합니까?
CBeTJlu4ok

1
@ Lothre1- remove메소드를 사용하는 경우에만 해당됩니다 . 대부분의 경우 DOM은 완전히 지워집니다. (터보 링크 등). 나는 내가 할 경우 메모리가 어떻게 영향을 받는지 궁금 document.body.innerHTML = ''...
수직 동기화

1
"개인 경험"이상의 것이 필요합니다. 하드 데이터 및 테스트, 더 이상 문서에없는 노드에서 메모리가 지속적으로 유지되는 방법에 대한 사양 링크가 필요합니다. 이는 증거없이 누군가의 단어를 신뢰하기에는 너무 중요합니다.)
vsync

1
@ Lothre1 Thanks-조금 더 깊이 파고 들어 jQuery가 일반 JavaScript와 다른 점에서 어떻게 작동하는지 알아 냈습니다. 답변을 업데이트했습니다.
dsgriffin

23

jQuery와 관련하여 :

.remove () 메소드는 DOM에서 요소를 가져옵니다. 요소 자체와 내부의 모든 요소를 ​​제거하려면 .remove ()를 사용하십시오. 요소 자체 외에도 요소와 관련된 모든 바인딩 된 이벤트 및 jQuery 데이터가 제거됩니다. 데이터와 이벤트를 제거하지 않고 요소를 제거하려면 .detach ()를 대신 사용하십시오.

참조 : http://api.jquery.com/remove/

jQuery v1.8.2 .remove()소스 코드 :

remove: function( selector, keepData ) {
    var elem,
        i = 0;

    for ( ; (elem = this[i]) != null; i++ ) {
        if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
            if ( !keepData && elem.nodeType === 1 ) {
                jQuery.cleanData( elem.getElementsByTagName("*") );
                jQuery.cleanData( [ elem ] );
            }

            if ( elem.parentNode ) {
                elem.parentNode.removeChild( elem );
            }
        }
    }

    return this;
}

분명히 jQuery는 node.removeChild()

이에 따르면 https://developer.mozilla.org/en-US/docs/DOM/Node.removeChild ,

The removed child node still exists in memory, but is no longer part of the DOM. You may reuse the removed node later in your code, via the oldChild object reference.

즉, 이벤트 리스너는 제거 될 수 있지만 node여전히 메모리에 존재합니다.


3
혼란을 추가하는 것만으로도 jQuery는 단순한 핸들러로 removeChild는 그렇지 않습니다. 또한 둘 다 나중에 다시 첨부하거나 (이 경우 분명히 메모리에 남아 있음) 던질 수있는 참조를 반환합니다 (이 경우 GC에 의해 선택되어 제거됨).
Oleg V. Volkov

알아 : D. 질문을 편집 한 사람은 어디입니까? 왜냐하면 나는 이전 질문에서 jquery를 사용하여 DOM 요소를 제거하는 것에 관한 무언가가 있다고 맹세 할 수있었습니다. 이제 내 대답은 단지 내 자존심을 치기 위해 일을 설명하는 것처럼 들립니다. 안녕하세요, 항상 downvote 수 있습니다
Sreenath S

8

이벤트 핸들러에서 클로저가있는 요소에 대한 참조를 유지하고 요소가 이벤트 핸들러에 대한 참조를 유지하는 경우 메모리 누수를보기 위해 주저하지 마십시오.

가비지 콜렉터는 순환 참조를 좋아하지 않습니다.

일반적인 메모리 누수 사례 : 개체에 요소가 있음을 인정합니다. 해당 요소는 핸들러를 참조합니다. 그리고 핸들러는 객체를 참조합니다. 객체는 다른 많은 객체를 나타냅니다. 이 개체는 컬렉션에서 참조를 제거하여 버린 것으로 생각되는 컬렉션의 일부였습니다. => 전체 객체와 객체가 참조 할 때까지 페이지가 종료 될 때까지 메모리에 남아 있습니다. => 예를 들어 객체 클래스에 대한 완전한 killing 메소드에 대해 생각하거나 mvc 프레임 워크를 신뢰해야합니다.

또한 Chrome 개발 도구의 유지 트리 부분을 사용하는 것을 망설이지 마십시오.


8

다른 답변을 확장하는 중 ...

위임 된 이벤트 핸들러는 요소 제거시 제거되지 않습니다.

$('body').on('click', '#someEl', function (event){
  console.log(event);
});

$('#someEL').remove(); // removing the element from DOM

이제 확인하십시오 :

$._data(document.body, 'events');

9
이벤트 핸들러는 #someEl가 아닌 body에 연결됩니다. 당연히 body가 아직 존재하는 한 핸들러를 제거하면 안됩니다.
Yangshun Tay

이것은 수동으로 제거 할 수 있습니다 : stackoverflow.com/questions/22400907/…
fangxing

7

와 관련 jQuery하여 다음과 같은 일반적인 메소드는 데이터 및 이벤트 핸들러와 같은 다른 구문도 제거합니다.

없애다()

요소 자체 외에도 요소와 관련된 모든 바인딩 된 이벤트 및 jQuery 데이터가 제거됩니다.

빈()

메모리 누수를 피하기 위해 jQuery는 요소 자체를 제거하기 전에 하위 요소에서 데이터 및 이벤트 핸들러와 같은 다른 구문을 제거합니다.

html ()

또한 jQuery는 해당 요소를 새 컨텐츠로 바꾸기 전에 하위 요소에서 데이터 및 이벤트 핸들러와 같은 다른 구성을 제거합니다.


2

예, 가비지 수집기에서도 제거합니다. 그래도 레거시 브라우저에서는 항상 그런 것은 아닙니다.


7
당신의 진술은 API 문서, 예제 등에 의해 뒷받침되어야합니다.
Paolo Fulgoni
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.