32 votes

Comment synchrone appel AJAX pourrait causer la fuite de mémoire?

Je comprends que ce sont les conseils généraux sur l'utilisation de l'ajax synchrone des appels, parce que les appels synchrones bloc de l'INTERFACE de rendu.

L'autre raison généralement invoquée est fuite de mémoire isssues avec synchrone AJAX.

À partir du MDN docs -

Remarque: Vous ne devriez pas utiliser synchrone XMLHttpRequests parce que, en raison de la nature de la nature asynchrone de la mise en réseau, il existe plusieurs des moyens de mémoire et des événements de fuite lors de l'utilisation des requêtes synchrones. L' seule exception est que les requêtes synchrones bien travailler à l'intérieur de Travailleurs.

Comment faire des appels synchrones pourrait provoquer des fuites de mémoire?

Je suis à la recherche d'un exemple pratique. Tous les pointeurs à toute la littérature sur ce sujet serait génial.

14voto

Esailija Points 74052

Si XHR est correctement mis en œuvre par spec, il ne sera pas de fuite:

Un objet XMLHttpRequest ne doit pas être nettoyée si son état est OUVERT, et l'envoyer (le drapeau est réglé, son état est HEADERS_RECEIVED, ou elle est à l'état de CHARGEMENT, et l'une des conditions suivantes est remplie:

Il a un ou plusieurs écouteurs d'événement enregistré dont le type est readystatechange, du progrès, de l'avortement, de l'erreur, de la charge, délai d'attente, ou loadend.

Le téléchargement complet du pavillon est détruit et les associés XMLHttpRequestUpload objet a un ou plusieurs écouteurs d'événement enregistré dont le type est le progrès, abandon, d'erreur, de la charge, délai d'attente, ou loadend.

Si un objet XMLHttpRequest est des ordures recueillies lors de sa connexion est toujours ouverte, l'agent utilisateur doit annuler toute instance de l'extraction algorithme ouvert par cet objet, en supprimant toutes les tâches en file d'attente pour eux, et le rejet de toutes les autres données reçues du réseau pour eux.

Donc, après vous frappez .send() l'objet XHR (et tout ce à quoi il fait référence) devient l'abri du GC. Cependant, toute erreur ou de succès va mettre la XHR en FAIT état et il devient assujetti à la GC de nouveau. Il ne importe pas si le XHR objet de synchronisation ou asynchrone. Dans le cas d'une longue requête de synchronisation de nouveau, il n'a pas d'importance parce que vous être coincé sur l'instruction send jusqu'à ce que le serveur répond.

Toutefois, selon cette diapositive , il n'a pas été correctement mis en œuvre, au moins dans Chrome/Chromium en 2012. Par spec, il n'y aurait pas besoin de faire appel .abort() depuis le FAIT de l'état signifie que l'objet XHR devrait déjà être normalement Pgcd.

Je ne trouve pas même la moindre preuve de la MDN déclaration, et je les ai contacté l'auteur par le biais de twitter.

3voto

Krasimir Points 6061

Je pense que les fuites de mémoire se produisent principalement parce que le garbage collector ne peut pas faire son travail. I. e. vous avez une référence à quelque chose et que le GC ne peux pas le supprimer. J'ai écrit un exemple simple:

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);
}

À l'exception du fait que la fonction synchrone blocs de beaucoup de choses, il y a une autre grande différence. La gestion des erreurs. Si vous utilisez getDataSync et retirez le bloc try-catch et actualisez la page, vous verrez qu'une erreur est levée. C'est parce que l'url n'existe pas, mais la question est maintenant de savoir comment garbage collector fonctionne lorsqu'une erreur est levée. Est-il efface tous les objets connectés à l'erreur, est-il maintient l'objet d'erreur ou quelque chose comme ça. Je serai heureux si quelqu'un en sait plus à ce sujet et d'écrire ici.

3voto

Dmitry Kaigorodov Points 543

Synchronisation XHR bloquer l'exécution du thread et tous les objets en fonction pile d'exécution de ce fil de GC.

E. g.:

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

Les Variables a et b sont bloqués ici (et l'intégralité de la pile trop). Donc, si GC commencé à travailler puis de synchroniser XHR a bloqué la pile, toutes les variables de pile sera marqué comme "survécu GC" et être déplacé à partir du début des tas à la plus persistante. Et d'un ton d'objets qui ne devrait pas survivre même le seul GC va vivre de nombreuses collectes et même les références de ces objets vont survivre à la GC.

Au sujet des demandes d'empiler des blocs de GC et de l'objet marqué comme à long live objets: voir la section Conservateur de Collecte des Ordures dans Griffant Notre Chemin De Retour À La Précision. Aussi, "marqué" objets GCed après l'habituel tas est GCed, et habituellement seulement si il y a encore besoin de libérer plus de mémoire (comme la collecte de marqué-et-modulée objs prend plus de temps).

Mise à JOUR: Est-il vraiment une fuite, et pas seulement en début de segment de mémoire inefficace solution? Il y a plusieurs choses à considérer.

  • Combien de temps ces objet est verrouillé après la demande en est fini?
  • Synchronisation XHR peut bloquer la pile pour une durée illimitée, XHR a pas de délai d'expiration de la propriété (dans tous les navigateurs IE), des problèmes de réseau ne sont pas rares.
  • Combien d'éléments de l'INTERFACE utilisateur sont verrouillés? Si ce bloc de 20M de la mémoire pour 1 sec == 200k de plomb en 2min. Considérer beaucoup de fond des onglets.
  • Considérons le cas lors de la synchronisation des blocs ton de ressources et de navigateur va pour le fichier d'échange
  • Quand un autre événement tente de modifier le DOM peut être bloqué par la synchronisation XHR, un autre thread est bloqué (et de l'ensemble de la pile trop)
  • Si l'utilisateur devra répéter les actions qui mènent à la synchronisation XHR, l' ensemble de la fenêtre du navigateur sera verrouillé. Les navigateurs utilise max=2 thread pour gérer des événements de fenêtre.
  • Même sans blocage ce qui consomme beaucoup d'OS et le navigateur de ressources internes: du fil, de la section critique de ressources, de l'INTERFACE utilisateur des ressources, DOM ... Imaginez que vous pouvez ouvrir en raison de problème de mémoire) 10 onglets avec des sites qui utilisent sync XHR et 100 onglets avec des sites qui utilisent async XHR. N'est-ce pas de fuite de mémoire.

3voto

Benubird Points 2337

Si l'appel synchrone est interrompu (c'est à dire par un utilisateur en cas de ré-utilisation de l'objet XMLHttpRequest) avant de terminer, puis la circulation du réseau de la requête peut être laissée en suspens, dans l'impossibilité d'être nettoyée.

C'est parce que, si l'objet qui a initié la demande n'existe pas lors de la demande de retour, le retour ne peut pas être complète, mais (si le navigateur est imparfaite) reste dans la mémoire. Vous pouvez facilement provoquer ce à l'aide de setTimeout pour supprimer l'objet de la requête après que la demande a été faite, mais avant il retourne.

Je me souviens que j'avais un gros problème avec cela, dans IE, autour de 2009, mais j'espère que les navigateurs modernes ne sont pas sensibles à cela. Certes, moderne bibliothèques (c'est à dire JQuery) pour éviter les situations dans lesquelles il pourrait se produire, permettant à des demandes sans avoir à y penser.

0voto

Tom Bell Points 122

Les fuites de mémoire synchrone à l'aide de requêtes AJAX sont souvent causés par:

  • à l'aide de la méthode setInterval/setTimout provoquant circulaire appels.
  • XmlHttpRequest - lorsque la référence est supprimée, de sorte xhr devient inaccessible

Fuite de mémoire se produit lorsque le navigateur pour une raison quelconque n'a pas de libérer la mémoire à partir d'objets qui ne sont plus nécessaires.

Cela peut se produire en raison de bogues de navigateur, les extensions de navigateur problèmes et, beaucoup plus rarement, nos erreurs dans l'architecture du code.

Voici un exemple d'une fuite de mémoire en cours de cause lors de l'exécution de la méthode setInterval dans un nouveau contexte:

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");
  }
});

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X