programing

동기화된 AJAX 콜이 메모리 누수를 일으킬 가능성이 얼마나 됩니까?

showcode 2023. 3. 16. 22:03
반응형

동기화된 AJAX 콜이 메모리 누수를 일으킬 가능성이 얼마나 됩니까?

동기 콜은 UI 렌더링을 차단하기 때문에 동기 AJAX 콜의 사용에 대해 이 일반적인 조언은 이해합니다.

다른 일반적인 이유는 동기 AJAX와의 메모리누전입니다.

MDN 문서에서 -

주의: 동기 XMLHttpRequests는 사용하지 마십시오.네트워킹의 본질적인 비동기 특성으로 인해 동기 요청을 사용할 때 메모리와 이벤트가 누출될 수 있는 다양한 방법이 다양합니다.유일한 예외는 동기요구가 워커 내부에서 잘 작동한다는 것입니다.

동기 콜이 메모리 누수의 원인이 되는 것은 무엇입니까?

나는 실용적인 예를 찾고 있다.이 주제에 관한 문헌에 대한 어떤 조언도 좋을 것이다.

사양에 따라 XHR이 올바르게 실장되어 있는 경우, 누출은 발생하지 않습니다.

XMLHttpRequest 객체는 상태가 OPEN이고 send() 플래그가 설정되어 있고 상태가 HEADES_RECEVED이거나 LOADING 상태이며 다음 중 하나에 해당하는 경우 가비지 수집되지 않아야 합니다.

여기에는 readystatechange, progress, abort, error, load, timeout 또는 loadend 타입의 이벤트청취자가 1개 이상 등록되어 있습니다.

업로드 완료 플래그가 설정 해제되어 있으며 연관된 XMLHttpRequestUpload 객체에 progress, abort, error, load, timeout 또는 loadend 유형의 이벤트청취자가 하나 이상 등록되어 있습니다.

XMLHttpRequest 객체가 연결이 열려 있는 동안 가비지가 수집될 경우 사용자 에이전트는 이 객체에 의해 열린 페치알고리즘 인스턴스를 취소하고 큐에 있는 작업을 폐기하고 네트워크로부터 수신한 추가 데이터를 폐기해야 합니다.

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.send()XHR 객체(및 XHR 객체가 참조하는 모든 것)는 GC에 대해 면역이 됩니다.다만, 에러나 성공했을 경우, XHR은 DONE 상태가 되어, GC의 대상이 됩니다.XHR 개체가 동기인지 비동기인지 여부는 전혀 문제가 되지 않습니다.다시 긴 동기화 요청이 있는 경우 서버가 응답할 때까지 send 문에 갇혀 있기 때문에 문제가 되지 않습니다.

그러나 이 슬라이드에 따르면 적어도 2012년 Chrome/Chromium에서는 올바르게 구현되지 않았습니다.사양에 따라 전화할 필요가 없습니다..abort()DONE 상태는 XHR 오브젝트가 이미 통상 GCd여야 함을 의미하기 때문입니다.

MDN의 진술을 뒷받침할 수 있는 증거조차 찾을 수 없어 트위터를 통해 작성자에게 연락을 취했습니다.

메모리 누수는 주로 쓰레기 수집기가 제 역할을 하지 못하기 때문에 일어나는 것이라고 생각합니다.즉, 참조가 있어 GC가 삭제할 수 없습니다.간단한 예시를 써봤습니다.

var getDataSync = function(url) {
    console.log("getDataSync");
    var request = new XMLHttpRequest();
    request.open('GET', url, false);  // `false` makes the request synchronous
    try {
        request.send(null);
        if(request.status === 200) {
            return request.responseText;
        } else {
            return "";
        }
    } catch(e) {
        console.log("!ERROR");
    }
}

var getDataAsync = function(url, callback) {
    console.log("getDataAsync");
    var xhr = new XMLHttpRequest();
    xhr.open("GET", url, true);
    xhr.onload = function (e) {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                callback(xhr.responseText);
            } else {
                callback("");
            }
        }
    };
    xhr.onerror = function (e) {
        callback("");
    };
    xhr.send(null);
}

var requestsMade = 0
var requests = 1;
var url = "http://missing-url";
for(var i=0; i<requests; i++, requestsMade++) {
    getDataSync(url);
    // getDataAsync(url);
}

동기 함수가 많은 것을 차단한다는 사실을 제외하면 또 다른 큰 차이가 있습니다.에러 처리getDataSync를 사용하여 try-catch 블록을 삭제하고 페이지를 새로 고치면 오류가 발생했음을 알 수 있습니다.그 이유는 URL이 존재하지 않기 때문입니다만, 여기서 문제는 에러가 발생했을 때의 가비지 콜렉터의 동작 방식입니다.에러와 관련된 모든 오브젝트를 클리어 하거나 에러 오브젝트를 보관하거나 합니다.누군가 그것에 대해 더 잘 알고 여기에 글을 써주셨으면 좋겠습니다.

동기 콜이 완료되기 전에 중단되면(즉 XMLHttpRequest 개체를 재사용하는 사용자 이벤트에 의해) 미결 네트워크 쿼리가 정지된 채로 남아 가비지 수집이 불가능합니다.

이는 요청을 시작한 개체가 요청을 반환할 때 존재하지 않으면 반환을 완료할 수 없지만 (브라우저가 불완전한 경우) 메모리에 남아 있기 때문입니다.setTimeout을 사용하면 요청이 이루어진 후 반환되기 전에 요청 개체를 쉽게 삭제할 수 있습니다.

2009년경 IE에서 큰 문제가 있었던 것으로 기억합니다만, 최신 브라우저는 이 문제에 민감하지 않았으면 합니다.확실히, 현대의 라이브러리(즉, JQuery)는, 그러한 상황이 발생하는 것을 방지하고, 이것에 대해 생각할 필요 없이 요구를 실시할 수 있습니다.

GC에서 XHR 블록 스레드 실행 및 이 스레드의 함수 실행 스택에 있는 모든 개체를 동기화합니다.

예:

function (b) { 
  var a = <big data>;
  <work with> a and b
  sync XHR
}

변수 a와 b는 여기서 차단됩니다(및 스택 전체도 마찬가지입니다.따라서 GC가 동작하기 시작하고 동기 XHR이 스택을 차단한 경우 모든 스택 변수가 "생존 GC"로 표시되며 초기 힙에서 보다 영속적인 스택으로 이동합니다.또한 단일 GC에서도 존속할 수 없는 오브젝트의 톤은 다수의 가비지 컬렉션에 존재하며 이들 오브젝트로부터의 참조도 GC에서 존속합니다.

클레임 스택 블록 GC 및 롱 라이브 개체로 표시된 개체에 대해: "정밀로 돌아가는 방법"의 "보수적 가비지 컬렉션" 섹션을 참조하십시오.또, 통상의 힙 후에 GC 처리되는 「마킹 끝난」오브젝트는, 통상은 메모리를 해방할 필요가 있는 경우에만(마킹 끝난 obj를 수집하는 데 시간이 걸립니다).

업데이트: 정말 누출일까요?얼리히프의 비효율적인 솔루션뿐만이 아닙니다.고려해야 할 사항이 몇 가지 있습니다.

  • 요청이 완료된 후 이러한 개체가 잠기는 기간은 얼마입니까?
  • Sync XHR은 스택을 무제한으로 차단할 수 있으며 XHR에는 타임아웃 속성이 없습니다(IE 이외의 브라우저에서는 모두).네트워크 문제는 드물지 않습니다.
  • 얼마나 많은 UI 요소가 잠겨 있습니까?단 1초 동안 20M의 메모리를 차단하면 == 2분 안에 200k 리드가 됩니다.많은 배경 탭을 고려합니다.
  • 단일 동기화가 리소스 톤을 차단하고 브라우저가 스왑 파일로 이동하는 경우를 고려하십시오.
  • 에서 다른 이벤트가 DOM을 변경하려고 하면 동기 XHR에 의해 차단될 수 있습니다.또 다른 스레드는 차단됩니다(및 그 스택 전체도 마찬가지입니다.
  • 사용자가 동기화 XHR로 이어지는 작업을 반복하면 브라우저 창 전체가 잠깁니다.브라우저는 max=2 스레드를 사용하여 창 이벤트를 처리합니다.
  • 차단하지 않아도 스레드, 크리티컬 섹션 리소스, UI 리소스, DOM 등 OS 및 브라우저 내부 리소스가 많이 소비됩니다.메모리 문제로 인해 동기 XHR을 사용하는 사이트에서는 10개의 탭을 열고 비동기 XHR을 사용하는 사이트에서는 100개의 탭을 열 수 있다고 가정합니다.메모리 누수 때문이 아니야

syncronous AJAX 요구를 사용한 메모리누전 원인은 다음과 같습니다.

  • setInterval/setTimeout을 사용하여 순환 콜을 발생시킵니다.
  • XmlHttpRequest - 참조가 삭제되면 xhr에 액세스할 수 없게 됩니다.

메모리 누수는 브라우저가 어떤 이유로 더 이상 필요하지 않은 객체에서 메모리를 해제하지 않을 때 발생합니다.

이 문제는 브라우저의 버그, 브라우저 확장 문제, 그리고 코드 아키텍처의 실수 때문에 발생할 수 있습니다.

다음으로 새로운 컨텍스트에서 setInterval을 실행할 때 메모리누설이 발생하는 예를 나타냅니다.

var
Context  = process.binding('evals').Context,
Script   = process.binding('evals').Script,
total    = 5000,
result   = null;

process.nextTick(function memory() {
  var mem = process.memoryUsage();
  console.log('rss:', Math.round(((mem.rss/1024)/1024)) + "MB");
  setTimeout(memory, 100);
});

console.log("STARTING");
process.nextTick(function run() {
  var context = new Context();

  context.setInterval = setInterval;

  Script.runInContext('setInterval(function() {}, 0);',
                      context, 'test.js');
  total--;
  if (total) {
    process.nextTick(run);
  } else {
    console.log("COMPLETE");
  }
});

언급URL : https://stackoverflow.com/questions/14364992/how-synchronous-ajax-call-could-cause-memory-leak

반응형