JavaScript setInterval () 메서드로 인해 메모리 누수가 발생합니까?
현재 JavaScript 기반 애니메이션 프로젝트를 개발 중입니다.
나는 것을 발견의 적절한 사용했다 setInterval()
, setTimeout()
심지어는 requestAnimationFrame
내 요청없이 할당 메모리, 자주 가비지 콜렉션 호출됩니다. 더 많은 GC 호출 = 깜박임 :-(
예를 들어; Google Chrome에서 init ()를 호출 하여 다음과 같은 간단한 코드 를 실행 하면 처음 20-30 초 동안 메모리 할당 + 가비지 수집이 괜찮습니다.
function init()
{
var ref = window.setInterval(function() { draw(); }, 50);
}
function draw()
{
return true
}
어떻게 든 1 분 내에 할당 된 메모리가 이상하게 증가하기 시작합니다! init ()는 한 번만 호출되므로 할당 된 메모리 크기가 증가하는 이유는 무엇입니까?
(편집 : 업로드 된 크롬 스크린 샷)
참고 # 1 : 예, 다음 setInterval () 전에 clearInterval () 호출을 시도했습니다. 문제는 동일합니다!
참고 # 2 : 문제를 분리하기 위해 위의 코드를 간단하고 어리석게 유지하고 있습니다.
편집 : Yury의 대답 이 더 좋습니다.
tl; dr IMO에는 메모리 누수가 없습니다. 양의 기울기는 단순히 setInterval 및 setTimeout의 효과입니다. 톱니 패턴에서 볼 수 있듯이 가비지 수집은 정의상 메모리 누수가 없음을 의미합니다. (나는 생각한다).
이 소위 "메모리 누수"를 해결할 방법이 있는지 잘 모르겠습니다. 이 경우 "메모리 누수"는 메모리 프로파일 러의 양의 기울기에서 볼 수 있듯이 메모리 사용량을 증가시키는 setInterval 함수에 대한 각 호출을 나타냅니다.
현실은 실제 메모리 누수가 없다는 것입니다. 가비지 수집기는 여전히 메모리를 수집 할 수 있습니다. 정의상 메모리 누수는 "컴퓨터 프로그램이 메모리를 확보했지만 운영 체제로 다시 릴리스하지 못할 때 발생합니다."
아래의 메모리 프로필에서 알 수 있듯이 메모리 누수가 발생하지 않습니다. 각 함수 호출에 따라 메모리 사용량이 증가하고 있습니다. OP는 이것이 계속 호출되는 동일한 함수이므로 메모리 증가가 없어야한다고 예상합니다. 그러나 이것은 사실이 아닙니다. 메모리는 각 함수 호출에 사용됩니다. 결국 쓰레기가 수거되어 톱니 모양이 만들어집니다.
간격을 재정렬하는 여러 방법을 탐색했으며 모두 동일한 톱니 패턴으로 이어집니다 (일부 시도는 참조가 유지되어 가비지 수집이 발생하지 않음).
function doIt() {
console.log("hai")
}
function a() {
doIt();
setTimeout(b, 50);
}
function b() {
doIt();
setTimeout(a, 50);
}
a();
http://fiddle.jshell.net/QNRSK/14/
function b() {
var a = setInterval(function() {
console.log("Hello");
clearInterval(a);
b();
}, 50);
}
b();
http://fiddle.jshell.net/QNRSK/17/
function init()
{
var ref = window.setInterval(function() { draw(); }, 50);
}
function draw()
{
console.log('Hello');
}
init();
http://fiddle.jshell.net/QNRSK/20/
function init()
{
window.ref = window.setInterval(function() { draw(); }, 50);
}
function draw()
{
console.log('Hello');
clearInterval(window.ref);
init();
}
init();
http://fiddle.jshell.net/QNRSK/21/
분명히 setTimeout
하고 setInterval
공식적으로 자바 스크립트의 일부 아니다 (따라서 그들은 V8의 일부가 아닌). 구현은 구현 자에게 달려 있습니다. node.js에서 setInterval 등의 구현을 살펴볼 것을 제안합니다.
여기서 문제는 코드 자체가 아니라 누출되지 않습니다. 타임 라인 패널이 구현되는 방식 때문입니다. 타임 라인이 이벤트를 기록 할 때 setInterval 콜백을 호출 할 때마다 JavaScript 스택 추적을 수집합니다. 스택 추적은 먼저 JS 힙에 할당 된 다음 원시 데이터 구조로 복사됩니다. 스택 추적이 원시 이벤트에 복사 된 후 JS 힙에서 가비지가됩니다. 이것은 그래프에 반영됩니다. 다음 호출 http://trac.webkit.org/browser/trunk/Source/WebCore/inspector/TimelineRecordFactory.cpp#L55를 비활성화하면 메모리 그래프가 평평 해집니다.
이 문제와 관련된 버그가 있습니다 : https://code.google.com/p/chromium/issues/detail?id=120186
함수를 호출 할 때마다 스택 프레임 이 생성 됩니다 . 다른 많은 언어와 달리 Javascript는 다른 모든 언어와 마찬가지로 스택 프레임을 힙에 저장합니다. 즉, 50ms마다 수행하는 함수를 호출 할 때마다 새 스택 프레임이 힙에 추가됩니다. 이것은 합산되어 결국 가비지 수집됩니다.
Javascript가 작동하는 방식을 고려할 때 불가피합니다. 이를 완화하기 위해 실제로 수행 할 수있는 유일한 방법은 스택 프레임을 가능한 한 작게 만드는 것입니다. 모든 구현이 그렇게 할 것이라고 확신합니다.
setInterval 및 깜박임에 대한 귀하의 의견에 응답하고 싶었습니다.
setInterval (), setTimeout () 및 requestAnimationFrame을 적절하게 사용하면 요청없이 메모리가 할당되고 가비지 수집 호출이 자주 발생한다는 것을 알았습니다. 더 많은 GC 호출 = 깜박임 :-(
setInterval 호출 을 setTimeout을 기반으로 하는 덜 사악한 자체 호출 함수로 대체 할 수 있습니다 . 폴 아일랜드 인 (비디오 이야기에서이 내가 jQuery를 소스에서 배운 10 가지라고 언급 여기 노트는 여기에 # 2 참조). 해야 할 일은 setInterval에 대한 호출을 setTimeout 이 수행해야하는 작업을 완료 한 후 setTimeout 을 통해 간접적으로 호출하는 함수로 바꾸는 것 입니다. 강연을 인용하려면 :
많은 사람들은 setInterval이 사악한 기능이라고 주장했습니다. 함수가 완료되었는지 여부에 관계없이 지정된 간격으로 함수를 계속 호출합니다.
위의 예제 코드를 사용하여 다음에서 init 함수를 업데이트 할 수 있습니다.
function init()
{
var ref = window.setInterval(function() { draw(); }, 50);
}
에:
function init()
{
//init stuff
//awesome code
//start rendering
drawLoop();
}
function drawLoop()
{
//do work
draw();
//queue more work
setTimeout(drawLoop, 50);
}
이것은 다음과 같은 이유로 약간 도움이 될 것입니다.
- draw() won't be called again by your rendering loop until it's completed
- as many of the above answers point out, all of the uninterrupted function calls from setInterval do put overhead on the browser.
- debugging is a bit easier as you're not interrupted by the continued firing of setInterval
Hope this helps!
Chrome is hardly seeing any memory pressure from your program (1.23 MB is very low memory usage by today's standards), so it probably does not think it needs to GC aggressively. If you modify your program to use more memory, you will see the garbage collector kick in. e.g. try this:
<!html>
<html>
<head>
<title>Where goes memory?</title>
</head>
<body>
Greetings!
<script>
function init()
{
var ref = window.setInterval(function() { draw(); }, 50);
}
function draw()
{
var ar = new Array();
for (var i = 0; i < 1e6; ++i) {
ar.push(Math.rand());
}
return true
}
init();
</script>
</body>
</html>
When I run this, I get a saw tooth memory usage pattern, peaking bellow around 13.5MB (again, pretty small by today's standards).
PS: Specifics of my browsers:
Google Chrome 23.0.1271.101 (Official Build 172594)
OS Mac OS X
WebKit 537.11 (@136278)
JavaScript V8 3.13.7.5
Flash 11.5.31.5
User Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.101 Safari/537.11
Try doing this without the anonymous function. For example:
function draw()
{
return true;
}
function init()
{
var ref = window.setInterval(draw, 50);
}
Does it still behave the same way?
There does not appear to be a memory leak. So long as the memory usage decreases again after GC, and the overall memory usage does not trend upward on average, there is no leak.
The "real" question I'm seeing here is that setInterval
does indeed use memory to operate, and it doesn't look like it should be allocating anything. In reality it needs to allocate a few things:
- It will need to allocate some stack space to execute both the anonymous function and the draw() routine.
- I don't know if needs to allocate any temporary data to perform the calls themselves (probably not)
- It needs to allocate a small amount of storage to hold that
true
return value fromdraw()
. - Internally, setInterval may allocate additional memory to re-schedule a reoccurring event (I don't know how it works internally, it may re-use the existing record).
- The JIT may try to trace that method, which would allocate additional storage for the trace and some metrics. The VM may determine this method is too small to trace it, I don't know exactly what all the thresholds are for turning tracing on or off. If you run this code long enough for the VM to identify it as "hot", it may allocate even more memory to hold the JIT compiled machine code (after which, I would expect average memory usage to decrease, because the generated machine code should allocate less memory in most cases)
Every time your anonymous function executes there is going to be some memory allocated. When those allocations add up to some threshold, the GC will kick in and clean up to bring you back down to a base level. The cycle will continue like this until you shut it off. This is expected behavior.
I also have the same problem. The client reported me that the memory of its computer was increasing every time more and more. At first I thought it was really strange that a web app could make that even though it was accessed by a simple browser. I noticed that this happened only in Chrome.
However, I started with a partner to investigate and through the developer tools of Chrome and the manager task we could see the memory increase the client had reported me.
그런 다음 jquery 함수 (요청 애니메이션 프레임)가 계속해서로드되어 시스템 메모리가 증가하는 것을 볼 수 있습니다. 그 후,이 게시물 덕분에 jquery 카운트 다운이 그렇게하는 것을 보았습니다. 매번 내 앱의 레이아웃에서 날짜를 업데이트하는 "SETINTERVAL"내부에 있기 때문입니다.
ASP.NET MVC로 작업하면서 BundleConfig와 레이아웃에서이 jquery 스크립트 카운트 다운을 종료하고 시간 카운트 다운을 다음 코드로 바꿉니다.
@(DateTime.Now.ToString("dd/MM/yyyy HH:mm"))
참고 URL : https://stackoverflow.com/questions/14034107/does-javascript-setinterval-method-cause-memory-leak
'code' 카테고리의 다른 글
Qt의 기본 사용자 브라우저에서 링크를 여는 방법은 무엇입니까? (0) | 2020.12.01 |
---|---|
for..in 및 hasOwnProperty (0) | 2020.12.01 |
"대기 가능한"메서드를 작성하는 방법은 무엇입니까? (0) | 2020.12.01 |
Pandas DataFrame 성능 (0) | 2020.12.01 |
Spring 데이터 jpa- 'entityManagerFactory'라는 이름의 빈이 정의되지 않았습니다. (0) | 2020.12.01 |