2

나는 잡지를 스매싱하면서 블로그를 읽었으며, 닫는 부분은 addy osmani memory efficient JS입니다. 나는 다음 함수가 largeStr에 대한 참조를 보유하고 있으며 GC가 그것을 주장 할 수 없다는 것을 이해한다.설명 Addy Osmani의 스매싱 잡지의 클로저 메모리 누수 예제

var a = function() { 
    var largeStr = new Array(1000000).join('x'); 
    return function() { 
    return largeStr; 
    }; 
}(); 

여기에서 언급 한 해결책은 largeStr에 대한 참조를 보유하지 않으며 GC가이를 청구 할 수 있습니다. 대신 그는 smallStr을 사용합니다.

var a = function() { 
    var smallStr = 'x'; 
    var largeStr = new Array(1000000).join('x'); 
    return function (n) { 
     return smallStr; 
    }; 
}(); 

큰 물건에 대한 참조가없는 Addy의 요지가 있습니다. 그러나, 나는 거기에 어떤 (더 나은) 방법이 궁금 해서요, 나는 첫 번째 기능의 기능을 가지고 그것을 효율적으로 메모리를 만들 수 있습니다.

+0

이 기사는 두 기능이 동일한 것을한다는 것을 의미하지는 않습니다. 그것들은 단지 예일뿐입니다. 하지만 반환 된 함수에 큰 문자열을 생성하는 코드를 옮길 수는 있습니다. 그것은 매번 새로운 것을 만들 것입니다. – Pointy

+0

같은 변형을 반복해서 만드는 것은 좋은 생각이 아닙니다. 하나의 글로벌 더 나은 것입니다 (처리 시간을 제외하고 ...) 사실 나는 이것을 설명하고 있었고 궁극적 인 해결책이 될 것이라고 궁금해. – KhanSharp

+0

글자가 어떻게되는지에 따라 다릅니다. 코드에 문자열이 거의 필요하지 않고 짧은 시간 동안 만 필요하면 매번 새로운 복사본을 만드는 것이 좋습니다. 코드가 자주 필요하다면 첫 번째 버전은 아마도 OK 일 것입니다 (그리고 전역 변수보다 낫습니다). – Pointy

답변

9

첫 번째 함수는 largeStr을 만들고이를 참조하는 함수를 반환합니다. 따라서 가비지 컬렉터가 변수에 여전히 포함되어있는 함수에 의해 여전히 사용 중이므로 largeStr을 해제 할 수 없다는 것은 논리적입니다.

두 번째 함수는 largeStr에 대한 지속적인 참조가 없으므로 가비지 수집기에서이를 해제 할 수 있습니다.

뭔가 큰 것에 대한 참조를 유지하면서 메모리를 사용하지 않는 방법이 있는지 묻는 것처럼 들립니다. 그 대답은 아니요

또한 기술적으로 "누출"이 아닙니다. 그들은 합법적 인 메모리 사용법입니다.


큰 문자열을 미리 작성하지 않아도 메모리 사용량없이 첫 번째 기능의 기능을 사용할 수 있습니다. 요구에 따라 작성한 경우 누군가가 함수를 호출 할 때까지 메모리를 소비하지 않습니다. 이는 실행 속도와 메모리 사용량 간의 직접적인 상충 관계임이 분명합니다. 그러나 여기에서 얻은 선택 사항입니다. 사전 캐시 된 경우 메모리를 소비합니다. 요구에 의해서만 빌드되면, 사용되기 전까지 메모리를 소비하지 않습니다.

여기에 사용 될 때까지 메모리를 소모하지 않습니다 수요 버전에 내장입니다 :이없는

var a = function() { 
    return function() { 
    return new Array(1000000).join('x'); 
    }; 
}(); 

가 둔각이 기록 될 수 있습니다. 반군 폐쇄가 없기 때문에 그것은 또한 단지이 될 수 있습니다

var a = function() { 
    return new Array(1000000).join('x'); 
} 

이 두 버전들이 때마다 a()가 호출되는 문자열을 생성하는 단점이 있지만, 아무것도 이제까지 영구적으로 캐시되지 않는 장점이있다. a()의 모든 사용이 완료되면 모든 것이 가비지 수집됩니다.


또는, 처음 사용하는 전용 캐시를 : 이것은 전혀 기억이 먼저 호출되고 a()에 대한 후속 호출이 다시 필요가 없습니다 a() 때까지 소비되지 않는 장점이있다

var a = function() { 
    var largeStr; 
    return function() { 
    if (!largeStr) { 
     largeStr = new Array(1000000).join('x'); 
    } 
    return largeStr; 
    }; 
}(); 

큰 문자열이지만 단일 largeStr은 만들어지면 가비지 수집되지 않습니다.

어느 것이 가장 좋습니까? 사용 패턴에 따라 다르며 디자인/사용에서 더 중요한 것은 무엇입니까?

+0

나는 비슷한 생각을하고있었습니다. 내가 어떤면을 놓치고 있는지 궁금해하고 있었다. 귀하의 답변에 감사드립니다. – KhanSharp

1

당신은 V8 폐쇄 메모리 누수가 발생하는 것은 매우 의도적 인 설정이 필요합니다

function create() { 
    var a = "x"; 
    var b = new Array(1000000).join('x'); 

    //Force context-allocation for b 
    (function(){b;}); 

    return function() { 
     return a; 
    }; 
} 

window.a = create(); 

b 코드에 액세스 할 수 없습니다하지만 당신은 완전히 window.a 제거 될 때까지 수집 할 수 없습니다

http://jsfiddle.net/bwPVe/

크롬에서 힙 스냅 샷을 만들면 알 수 있습니다.