Simple Jquery Ajax appel fuit la mémoire dans Internet Explorer

j'ai créé une page Web qui fait un appel Ajax chaque seconde. Dans Internet Explorer 7, il fuit mal La mémoire (20 Mo en environ 15 minutes).

le programme est très simple. Il exécute juste une fonction JavaScript qui fait un appel Ajax. Le serveur renvoie une chaîne vide, et le code JavaScript ne fait rien avec. J'utilise setTimeout pour exécuter la fonction à chaque seconde, et j'utilise Drip pour regarder la chose.

ici est la source:

<html>
  <head>
    <script type="text/javascript" src="http://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load('jquery', '1.4.2');
      google.load('jqueryui', '1.7.2');
    </script>
    <script type="text/javascript">
      setTimeout('testJunk()',1000);
      function testJunk() {
        $.ajax({ url: 'http://xxxxxxxxxxxxxx/test', // The url returns an empty string
                 dataType: 'html',
                 success: function(data){}
               });
        setTimeout('testJunk()',1000)
      }
    </script>
  </head>
  <body>
    Why is memory usage going up?
  </body>
</html>

comment colmater cette fuite? J'ai une vraie application qui met à jour une grande table de cette façon, mais laissée sans surveillance elle va engloutir gigaoctets de mémoire.

Modifier : ok, donc après quelques bonnes suggestions, j'ai modifié le code pour:

<html>
  <head>
    <script type="text/javascript" src="http://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load('jquery', '1.4.2');
      google.load('jqueryui', '1.7.2');
    </script>
    <script type="text/javascript">
      setTimeout(testJunk,1000);
      function testJunk() {
        $.ajax({ url: 'http://xxxxxxxxxxxxxx/test', // The url returns an empty string
                 dataType: 'html',
                 success: function(data){setTimeout(testJunk,1000)}
               });
      }
    </script>
  </head>
  <body>
    Why is memory usage going up?
  </body>
</html>

cela ne semblait pas faire de différence, cependant. Je ne fais rien avec le DOM, et si je commente L'appel Ajax, la mémoire la fuite s'arrête. On dirait que la fuite est entièrement dans L'appel D'Ajax. Ne Ajax de jQuery intrinsèquement créer une sorte de référence circulaire, et si oui, comment puis-je libre? Au fait, ça ne fuit pas dans Firefox.

Quelqu'un a suggéré d'exécuter le test dans une autre VM et voir si les résultats sont les mêmes. Plutôt que de configurer une autre VM, j'ai trouvé un ordinateur portable qui exécutait XP Home avec Internet Explorer 8. Il présente le même problème.

j'ai essayé un peu plus vieux versions de jQuery et obtenu de meilleurs résultats, mais le problème n'a pas disparu entièrement jusqu'à ce que je abandonné Ajax en jQuery et est allé avec plus traditionnel (et laid) Ajax.

40
demandé sur Peter Mortensen 2010-03-12 01:09:44

8 réponses

voici un lien vers le bug sur jQuery, avec ceci comme solution suggérée pour jQuery 1.4.2:

--- jquery-1.4.2.js     2010-04-08 12:10:20.000000000 -0700
+++ jquery-1.4.2.js.fixed       2010-04-08 12:10:38.000000000 -0700
@@ -5219,7 +5219,7 @@

                            // Stop memory leaks
                            if ( s.async ) {
-                                       xhr = null;
+                                       xhr.onreadystatechange = null; xhr.abort = null; xhr = null;
                            }
                    }
            };

NOTE : ceci est officiellement fixé dans jQuery 1.4.4, donc votre meilleur pari est de juste mettre à niveau maintenant.

19
répondu Ryley 2010-12-31 19:15:15

le problème semble être avec jQuery 1.4 dans Internet Explorer, et dans une moindre mesure, les versions 1.2 et 1.3.

1.4.0, 1.4.1 et 1.4.2 présentaient toutes une grave fuite de mémoire.

1.2.3, 1.2.6, 1.3.0, 1.3.1, et 1.3.2 toutes présentaient une fuite beaucoup plus faible (environ 100 KB après 10 minutes).

j'ai également essayé une version de mon programme qui appelle Ajax d'une manière plus traditionnelle:

<html>
  <head>
    <script language="javascript" type="text/javascript">
      function getHTTPObject() {
        var xmlhttp;
        /*@cc_on
        @if (@_jscript_version >= 5)
          try {
            xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
          } catch (e) {
            try {
              xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            } catch (E) {
              xmlhttp = false;
            }
          }
        @else
        xmlhttp = false;
        @end @*/
        if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
          try {
            xmlhttp = new XMLHttpRequest();
            if (xmlhttp.overrideMimeType) {
              xmlhttp.overrideMimeType("text/xml"); 
            }
          } catch (e) {
            xmlhttp = false;
          }
        }
        return xmlhttp;
      }
      var ajaxObject = getHTTPObject();
      setTimeout(testJunk,1000);
      function testJunk() {
        ajaxObject.open('POST', 'http://XXXXXXXXXXXXXXX/delme2', true);
        ajaxObject.onreadystatechange = handleAjaxResponse;
        ajaxObject.send(null);
      }
      function handleAjaxResponse() {
        if (ajaxObject.readyState==4) {
          setTimeout(testJunk,1000);
        }
      }
    </script>
  </head>
  <body>
    <div id="test">Why is memory usage going up?</div>
  </body>
</html>

This se débarrasser de la fuite entièrement.

on dirait que je vais devoir répéter les appels Ajax à l'ancienne jusqu'à ce que les gens de jQuery règlent ce problème.

8
répondu Thomas Lane 2010-10-20 09:34:22

j'ai rencontré le même problème et j'ai été perplexe toute la matinée ... jusqu'à il y a quelques instants. Le problème est une référence circulaire qui est créée lorsque vous définissez le handler onreadystatechange , C'est-à-dire qu'il n'est pas assez intelligent pour casser. La solution est donc de rompre explicitement. Cependant, évidemment, vous ne pouvez pas le faire de l'intérieur du handler lui-même (bien qu'il serait commode si vous le pouviez!).

La magie de la déclaration:

delete request['onreadystatechange'];

vous avez besoin pour conserver un enregistrement de chaque XMLHttpRequest objet pour lequel vous avez placé onreadystatechange . Puis, à un certain point après readyState va à 4, Faire votre magie sur l'objet. Si vous effectuez déjà un sondage AJAX répété, l'endroit logique pour vérifier les requêtes de nettoyage serait dans la même boucle de sondage. J'ai défini un objet simple RequestTracker pour gérer mes requêtes.

Cela a fonctionné pour moi; j'ai vérifié qu'il a résolu la fuite. Voici un lien en particulier, qui a ouvert la voie (je ne posterais plus, mais StackOverflow n'est pas de me laisser):

7
répondu Haw-Bin 2010-04-02 15:59:04

eval() va manger la mémoire à coup sûr (eval arrive quand passer une chaîne de caractères à setTimeout pour évaluer), ne l'utilisez pas dans les tests:

setTimeout('testJunk()',1000);

devrait être:

setTimeout(testJunk, 1000);

aussi une meilleure utilisation globale serait setInterval() pour une opération répétée comme vous voulez, essayez ceci:

setInterval(testJunk, 1000);
5
répondu Nick Craver 2010-03-11 22:13:38

un problème avec votre code est que si votre requête ajax commence à prendre un certain temps vous allez commencer à inonder le navigateur et le serveur avec la requête ajax vous devriez vraiment attendre jusqu'à ce que le navigateur obtient un retour du serveur avant de lancer le prochain.

function testJunk() {
    $.ajax({ url: 'http://xxxxxxxxxxxxxx/test', // The url returns an empty string
        dataType: 'html',
        complete: function(data){
            setTimeout(testJunk,1000);
        }
    });
}
testJunk();
0
répondu PetersenDidIt 2010-03-11 22:33:24

j'ai vu ça, et je ne crois pas que ce soit une fuite de mémoire en soi. C'est juste que la requête Ajax retourne sans données à cause de la mise en cache.

ajouter contrôle de cache délibéré, comme dans:

$.ajax({ url: 'http://xxxxxxxxxxxxxx/test', // The url returns an empty string
         dataType: 'html',
         cache: false,
         success: function(data){}
    });
    setTimeout('testJunk()',1000)

c'est l'une de ces choses où les choses tombent entre les mailles du filet, c'est-à-dire qu'il fait une chose spécifique avec la mise en cache et XMLHttpRequest et jQuery n'utilise pas cache off par défaut.

0
répondu nic ferrier 2010-10-20 09:28:52

vient de le découvrir moi-même. Je pensais que c'était en rapport avec la bibliothèque de L'interface, mais elle a disparu après que j'ai changé en jQuery 1.5. pour la version 1.4.2 que j'utilisais. (1.4.4 ne semble pas résoudre le problème).

0
répondu James Wiseman 2011-02-21 09:59:49

si vous utilisez le setinterval en javascript et que vous ne l'effacez pas correctement, le minuteur peut démarrer plusieurs fois, provoquant une pile d'appels.

essayez quelque chose comme

var myVar = setInterval(function() { clear() }, 5000);

function clear() { 
    clearInterval(myVar); 
    GetData("ServiceLibrary","GetCalls",sdata,Complete);
};
0
répondu sully 2014-02-24 22:57:02