JavaScript 가비지 수집이란 무엇입니까?


답변:


192

에릭 리퍼 트 ​​(Eric Lippert)는 이 주제에 대한 자세한 블로그 게시물을 작성했습니다 ( VBScript와 비교 ). 보다 정확하게, 그는 JavaScript와 매우 유사하지만 Microsoft가 자체 ECMAScript를 구현 한 JScript 에 대해 썼습니다 . Internet Explorer의 JavaScript 엔진에서 대부분의 동작이 동일하다고 가정 할 수 있습니다. 물론 구현은 브라우저마다 다르지만 여러 일반적인 원칙을 취하여 다른 브라우저에 적용 할 수 있다고 생각합니다.

해당 페이지에서 인용 :

JScript는 비 생성 마크 앤 스윕 가비지 수집기를 사용합니다. 다음과 같이 작동합니다.

  • "범위 내"인 모든 변수를 "스 캐빈 저"라고합니다. 스 캐빈 저는 숫자, 개체, 문자열 등을 가리킬 수 있습니다. 스 캐빈 저 목록을 유지합니다. 변수가 범위에 도달하면 변수가 스캐브 목록으로 이동하고 범위를 벗어날 때 스캐브 목록에서 변수가 이동합니다.

  • 때때로 가비지 수집기가 실행됩니다. 먼저 모든 객체, 변수, 문자열 등에 GC가 추적하는 모든 메모리에 "마크"를 표시합니다. (JScript는 내부적으로 VARIANT 데이터 구조를 사용하며 해당 구조에는 사용되지 않는 추가 비트가 많이 있으므로 그중 하나만 설정합니다.)

  • 둘째, 청소부에서 표시를 제거하고 청소부 참조의 전 이적 폐쇄를 제거합니다. 따라서 scavenger 객체가 nonscavenger 객체를 참조하는 경우 비 scavenger 및 참조하는 모든 비트를 지 웁니다. (저는 이전 게시물과 다른 의미로 "폐쇄"라는 단어를 사용하고 있습니다.)

  • 이 시점에서 우리는 여전히 표시된 모든 메모리가 범위 내 변수의 경로에 도달 할 수없는 할당 된 메모리라는 것을 알고 있습니다. 이러한 객체는 모두 자체적으로 분해되도록 지시되어있어 순환 참조를 파괴합니다.

가비지 컬렉션의 주요 목적은 프로그래머를 허용하는 것입니다 되지 는 적어도 어떻게 가비지 컬렉션 작품의 거친 생각을 가지고 항상 도움이됩니다 - 물론 전혀 때때로이 피 년대 불구하고, 자신이 만든 객체와 사용의 메모리 관리에 대한 걱정에 .

과거 메모 : 이전 버전의 답변은 delete운영자 를 잘못 참조했습니다 . JavaScript 에서 delete연산자는 객체에서 속성을 제거하며delete C / C ++ 와는 완전히 다릅니다 .


27
애플 가이드에 결함이 있습니다 delete. 예를 들어, 첫 번째 예에서는 delete foo먼저을 통해 이벤트 리스너를 제거한 window.removeEventListener()다음을 사용 foo = null하여 변수를 덮어 씁니다. IE에서는 delete window.foo(그러나 그렇지 delete foo는 않지만 ) foo글로벌 한 경우에도 효과 가 있었지만 FF 또는 오페라에서는 작동하지 않았을 것입니다
Christoph

3
Eric의 기사는 "역사적 목적으로 만"고려되어야합니다. 그러나 여전히 유익합니다.
피터 이반

2
참고 사항-IE 6 및 7은 비 생성 마크 앤 스윕 가비지 수집기를 사용하지 마십시오. 가비지 수집의 순환 참조 문제에 더 취약한 간단한 참조 계산 가비지 수집기를 사용합니다.
Doug

1
ECMAScript delete는 문장이 아닌 단항 연산자 (표현식)입니다 (예 :) delete 0, delete 0, delete 3. 식 문으로 표현하면 문처럼 보입니다.
Hydroper

그러나 당시의 답변은 현재 구식입니다. 2012 년 현재 최신 브라우저는 마크 / 스위프 알고리즘을 사용합니다. 따라서 더 이상 범위에 의존하지 않습니다. 참조 : developer.mozilla.org/en-US/docs/Web/JavaScript/…
sksallaj

52

DOM 객체가 관련된 순환 참조에주의하십시오 :

JavaScript의 메모리 누수 패턴

객체에 대한 활성 참조가없는 경우에만 메모리를 회수 할 수 있습니다. 일부 JS 엔진은 내부 함수에서 실제로 참조되는 변수를 확인하지 않고 둘러싸는 함수의 모든 로컬 변수를 유지하기 때문에 클로저 및 이벤트 핸들러의 일반적인 함정입니다.

다음은 간단한 예입니다.

function init() {
    var bigString = new Array(1000).join('xxx');
    var foo = document.getElementById('foo');
    foo.onclick = function() {
        // this might create a closure over `bigString`,
        // even if `bigString` isn't referenced anywhere!
    };
}

순진한 JS 구현은 bigString이벤트 핸들러가있는 한 수집 할 수 없습니다 . 이 예를 들어 문제 설정 해결 방법에는 여러 가지가 있습니다 bigString = null의 끝은 init()( delete것이다 지역 변수와 함수 인수하지 작업 : delete개체를 삭제합니다 속성, 변수 개체에 액세스 할 수 없습니다 - 엄격 모드에서 ES5가도를 던질 것이다 ReferenceError당신이 시도하는 경우 지역 변수를 삭제하십시오!).

메모리 소비를 걱정하는 경우 가능한 한 불필요한 클로저를 피하는 것이 좋습니다.


20
DOM 순환 참조 버그는 JScript에만 해당됩니다. 다른 브라우저에서는 IE를 겪지 않습니다. 사실 ECMAScript 사양에 따르면 GC가 이러한주기를 처리 할 수 ​​있어야한다고 명시 적으로 명시되어 있습니다.-/
olliej

@ olliej : ECMAScript spec에 GC에 대한 언급이 없습니다 .
야누스 Troelsen


16

블로그에서 가져온 좋은 인용문

DOM 구성 요소는 JScript 구성 요소와 마찬가지로 "가비지 수집"으로, 구성 요소 중 하나에서 개체를 만든 다음 해당 개체를 추적하지 않으면 결국 정리됩니다.

예를 들면 다음과 같습니다.

function makeABigObject() {
var bigArray = new Array(20000);
}

해당 함수를 호출하면 JScript 구성 요소는 함수 내에서 액세스 할 수있는 객체 (이름이 bigArray)를 만듭니다. 그러나 함수가 리턴 되 자마자 더 이상 참조 할 수있는 방법이 없기 때문에 bigArray를 "잃어 버렸습니다". JScript 구성 요소는 사용자가 구성 요소를 잃어 버렸음을 인식하여 bigArray를 정리하여 메모리를 회수합니다. DOM 구성 요소에서도 동일한 종류의 기능이 작동합니다. document.createElement('div'), 또는 이와 유사한 것을 말하면 DOM 구성 요소가 객체를 생성합니다. 어떻게 든 그 객체를 추적하지 못하면 DOM 구성 요소가 관련을 정리합니다.


13

내가 아는 한, JavaScript 객체는 객체에 대한 참조가 없을 때 주기적으로 가비지 수집됩니다. 자동으로 발생하지만 C ++ 수준에서 작동 방식에 대해 더 자세히 알고 싶다면 WebKit 또는 V8 소스 코드를 살펴 보는 것이 좋습니다.

일반적으로 IE 5.5 및 이전 버전의 IE 6과 같은 이전 브라우저 및 현재 버전과 같은 오래된 브라우저에서 클로저는 체크하지 않으면 메모리를 소모하는 순환 참조를 생성합니다. 클로저에 대한 특별한 경우에는 dom 객체에 대한 JavaScript 참조를 추가하고 JavaScript 객체를 다시 참조하는 DOM 객체에 객체를 추가했을 때였습니다. 기본적으로 그것은 수집 될 수 없으며 결국 충돌을 일으키기 위해 반복되는 테스트 응용 프로그램에서 OS가 불안정하게됩니다. 실제로 이러한 누출은 일반적으로 작지만 코드를 깨끗하게 유지하려면 DOM 객체에 대한 JavaScript 참조를 삭제해야합니다.

일반적으로 delete 키워드를 사용하여 특히 모바일 웹 개발에서 수신하고 처리해야하는 JSON 데이터와 같은 큰 객체를 즉시 역 참조하는 것이 좋습니다. 이것은 GC의 다음 스윕이 해당 오브젝트를 제거하고 메모리를 비우도록합니다.


최신 버전의 IE에서 JavaScript-> DOM-> JavaScript 순환 참조 문제가 해결 되었습니까? 그렇다면 언제부터? 나는 그것이 건축 적으로 매우 깊고 고쳐질 것 같지 않다고 생각했다. 소스가 있습니까?
erikkallen

일화 적으로. IE 8에서 깨진 모드가 아니라 표준 모드로 실행되는 미친 누출을 보지 못했습니다. 응답을 조정하겠습니다.
Heat Miser

1
@ erikkallen : 예, GC 버그는 IE 버전 8 이상에서 수정되었습니다. 이전 버전은 매우 순진 가비지 수집 알고리즘을 사용했기 때문에 서로 참조하는 객체 쌍을 GC 할 수 없었습니다. 최신 mark-and-sweep스타일 알고리즘 이이를 처리합니다 .
kumarharsh

6

가비지 수집 (GC)은 더 이상 필요없는 객체를 제거하여 자동 메모리 관리의 한 형태입니다.

메모리와 관련된 모든 프로세스는 다음 단계를 수행하십시오.

1-필요한 메모리 공간을 할당하십시오

2-일부 처리 수행

3-이 메모리 공간을 비우십시오

더 이상 필요하지 않은 객체를 감지하는 데 사용되는 두 가지 주요 알고리즘이 있습니다.

참조 카운트 가비지 콜렉션 :이 알고리즘은 "더 이상 오브젝트가 필요하지 않음"의 정의를 "오브젝트가 참조하는 오브젝트가없는 오브젝트"로 정의하며, 참조 점이 없으면 오브젝트가 제거됩니다.

Mark-and-Sweep 알고리즘 : 각 객체를 루트 소스에 연결합니다. 어떤 객체도 루트 나 다른 객체에 연결되지 않습니다. 이 개체는 제거됩니다.

현재 두 번째 알고리즘을 사용하는 최신 브라우저.


1
이 소스를 추가하려면 MDN을 참조하십시오 : developer.mozilla.org/en-US/docs/Web/JavaScript/…
Xenos

4

"컴퓨터 과학에서 가비지 수집 (GC)은 자동 메모리 관리의 한 형태입니다. 가비지 수집기 또는 수집기 만 가비지 또는 응용 프로그램에서 다시 액세스하거나 변경하지 않는 개체가 사용한 메모리를 회수하려고 시도합니다."

모든 JavaScript 엔진에는 자체 가비지 수집기가 있으며 다를 수 있습니다. 대부분의 경우 그들이해야 할 일을하기 때문에 처리 할 필요가 없습니다.

더 나은 코드를 작성하는 것은 주로 프로그래밍 원칙, 언어 및 특정 구현을 얼마나 잘 알고 있는지에 달려 있습니다.


1

JavaScript 가비지 수집이란 무엇입니까?

이것을 확인 하십시오

더 나은 코드를 작성하기 위해 웹 프로그래머가 JavaScript 가비지 콜렉션에 대해 이해하는 것이 중요합니까?

Javascript에서는 메모리 할당 및 할당 해제에 신경 쓰지 않습니다. 모든 문제는 Javascript 인터프리터에게 요구됩니다. Javascript에서 누수가 여전히 가능하지만 해석기의 버그입니다. 이 주제에 관심이 있으시면 www.memorymanagement.org를 참조하십시오.


기사에서 링크 된 다양한 메모리 관리 시스템 중 JavaScript가 사용하는 시스템은 무엇입니까? "자바 스크립트에서 유출은 여전히 ​​가능하지만 통역사의 버그입니다." 그렇다고 JS 프로그래머가 전체 문제를 무시할 수 있다는 의미는 아닙니다. 예를 들어, 이전 버전의 IE에는 JS 코드에서 해결할 수있는 잘 알려진 JS <-> DOM 순환 참조 문제가 있습니다. 또한, 방법 JS 폐쇄 작업은 디자인 기능이 아니라 버그,하지만 당신이 "부적절"클로저를 사용하는 경우는 (내가있어 의도 한 것보다 메모리의 큰 덩어리를 묶을 수 없는 그들을 사용하지 않는 말).
nnnnnn

3
메모리 누수는 JavaScript에서 가장 큰 문제입니다. 간단한 "대학 프로젝트"응용 프로그램을 작성하는 경우 걱정할 필요가 없습니다. 그러나 고성능 엔터프라이즈 레벨 앱을 작성하기 시작하면 JavaScript의 메모리 관리가 필수입니다.
Doug

1

Windows에서는 Drip.exe 를 사용 하여 메모리 누수를 찾거나 무료 메모리 루틴이 작동하는지 확인할 수 있습니다.

정말 간단합니다. 웹 사이트 URL을 입력하면 통합 IE 렌더러의 메모리 소비가 표시됩니다. 그런 다음 새로 고침을 누르면 메모리가 증가하면 웹 페이지 어딘가에서 메모리 누수가 발견됩니다. 그러나 이것은 메모리를 해제하는 루틴이 IE에서 작동하는지 확인하는 데 매우 유용합니다.


1

참조 유형 은 오브젝트를 지정된 변수에 직접 저장하지 않으므로이 예제의 오브젝트 변수에는 실제로 오브젝트 인스턴스가 포함되지 않습니다. 대신, 객체가 존재하는 메모리의 위치에 대한 포인터 (또는 참조)를 보유합니다.

var object = new Object();

하나의 변수를 다른 변수에 할당하면 각 변수는 포인터의 사본을 가져 오며 둘 다 여전히 메모리에서 동일한 객체를 참조합니다.

var object1 = new Object();
var object2 = object1;

하나의 객체를 가리키는 두 개의 변수

JavaScript는 가비지 수집 언어이므로 참조 유형을 사용할 때 메모리 할당에 대해 걱정할 필요가 없습니다. 그러나 가비지 수집기가 해당 메모리를 해제 할 수 있도록 더 이상 필요하지 않은 객체 를 역 참조 하는 것이 가장 좋습니다 . 이를 수행하는 가장 좋은 방법은 객체 변수를 null로 설정하는 것입니다.

var object1 = new Object();
// do something
object1 = null; // dereference

객체 참조 해제 는 수백만 개의 객체를 사용하는 대규모 응용 프로그램에서 특히 중요합니다.

객체 지향 JavaScript의 원리-NICHOLAS C. ZAKAS

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.