2008-12-03 4 views
8

J'ai une page Web qui utilise jquery pour recevoir des informations sur les produits lorsque les gens regardent les choses et affiche ensuite les dernières images de produits qui ont été vues. Ceci est un rappel jquery AJAX qui ressemble beaucoup à ceci:Javascript + tags IMG = fuite de mémoire. Y a-t-il une meilleure manière de faire cela?

if(number_of_things_seen > 10) { 
    $('#shots li:last-child').remove(); 
} 

$('<li><img src="' + p.ProductImageSmall + '"></li>').prependTo('#shots'); 

Cependant, il semble fuir un peu de mémoire. Visuellement, il fait la bonne chose, mais l'empreinte croît indéfiniment.

L'inspecteur DOM de Safari montre que le DOM est ce que j'attendrais, mais il semble maintenir des références à chaque image qu'il a affichée (comme vu dans this screenshot au cas où quelqu'un serait intéressé).

J'ai ajouté

$('#shots li:last-child img').remove(); 

à la déclaration de retrait sans effet notable.

Y a-t-il un peu de magie nécessaire pour que le navigateur lance une partie de ce genre de choses?

+0

Avez-vous réussi à trouver la fuite? Je serais intéressé si vous l'avez fait. – Tomalak

+0

Non. Il fuit toujours comme un fou. J'ai fait une version différente de l'application qui a un mécanisme d'affichage considérablement différent, mais je vois toujours les images couler. – Dustin

+0

Lorsque vous écrivez un scénario de test, dites une seule balise img et une boucle JavaScript qui remplace son attribut src d'un tas d'URL (pas de structure JS, juste un grand tableau statique d'URL et une boucle à trois lignes) - est-ce encore fuite? Si oui, vous n'avez pas de chance, sinon tout peut être réparé. – Tomalak

Répondre

1

Pouvez-vous essayer de changer le src du dernier enfant et voir si cela fait une différence? Vous pouvez ensuite déplacer cet élément pour être le premier enfant

//not tested 

var $list=$('#shots>li'); 
$list.filter(':last-child').children('img') 
.attr('src', p.ProductImageSmall) 
.parent() 
.insertBefore($list.eq(0)); 
+0

J'aime le code que cette suggestion a conduit à, mais les images ne semblent toujours pas disparaître. – Dustin

+0

Dustin quand vous dites que les images ne disparaissent pas pouvez-vous clarifier? Voulez-vous dire qu'il n'échange pas les images? – redsquare

+0

Il est étrange que l'enlèvement de jquery soit optimisé pour éviter les fuites. c'est peut-être la création des objets xhr qui fuient? – redsquare

0

combien de temps vous avez observé cette « croissance indéfinie »? certaines implémentations de garbage collector ne remettent pas nécessairement la mémoire à l'OS si rapidement, voire pas du tout. pouvez-vous distiller ce que vous essayez de faire dans un vrai test simple (par exemple, le réglage de src de l'image encore et encore) sans ajax ou callbacks? avez-vous/pouvez-vous essayer ceci avec les autres navigateurs?

+0

Je le laisse tourner pendant plusieurs heures et quelques milliers de produits défilent. Je ne pouvais pas voir qu'il a jamais libéré quoi que ce soit. – Dustin

+0

Est-ce que cela risque de se produire dans un cas réel? – redsquare

+0

@redsquare Certainement. Ceci visualise l'utilisation du produit d'une entreprise. Je m'attends à ce qu'ils laissent toute la journée. Les images sont très belles, mais il se peut que je doive les tirer si le navigateur va exploser les jours chargés. – Dustin

1

De l'Mozilla Developer Center on removeChild():

Le nœud enfant enlevé existe encore en mémoire, mais ne fait plus partie du DOM. Vous pouvez réutiliser le nœud supprimé plus tard dans votre code, via la référence d'objet oldChild.

Ceci est la clé - réutilisez l'enfant supprimé, au lieu d'en créer un nouveau à plusieurs reprises.

// I'm sure there is a nicer way to do it in jQuery 
if(number_of_things_seen > 10) { 
    var shots = document.getElementById("shots"); 
    var li = shots.getElementsByTagName("LI"); 
    var move = shots.removeChild(li[li.length-1]); 
    move.getElementsByTagName("IMG")[0].src = p.ProductImageSmall; 
    shots.insertBefore(move, li[0]); 
} 
+0

C'est à peu près ce que redsquare m'a fait faire. Cela fonctionne, mais cela n'empêche pas la fuite. :/ – Dustin

+0

Est-ce que ça pousse la même chose si vous venez de déplacer l'enfant sans toucher le src? – Tomalak

+1

Et - avez-vous réellement essayé * non * d'utiliser jQuery pour cela (essayez par exemple l'approche JS uniquement)? Peut-être que jQuery est toujours responsable. – Tomalak

0

ok j'ai construit un harnais de test pour cela, il saisit au hasard une nouvelle image et utilise mon remplacer le code src

voir http://pastebin.me/4936458820c43

+0

Avoir à dire ne pas aimer ce que je vois ici .... – redsquare

+0

Je ne vois pas le nombre d'images qui poussent en safari. Je suppose que c'est plutôt bon. Je pense que c'est +1 la théorie du xhr. Cependant, je ne comprends pas très bien qui a la référence img. – Dustin

+0

Peut-être que je vais essayer IRC demain et voir si quelqu'un peut me dire la différence entre ce que vous faites et ce que je fais. Merci pour votre aide jusqu'à maintenant). – Dustin

0

Dustin, Il semble que la déclaration insertBefore dans mon code causait des problèmes. Si vous voyez ce nouveau test, l'utilisation de la mémoire reste assez statique même si je vide le dernier enfant et insère un nouveau fragment dom. Effectue mieux que la dernière tentative.

http://pastebin.me/4936519fea2cf

1

est l'empreinte vraiment un problème?

Je pense que Safari met en cache toutes les images tant que vous restez sur le même site et que vous ne pouvez rien y faire. Si vous êtes chanceux Safari libère des objets non-nécessaires après qu'une limite soit atteinte.

La raison de ce comportement est que Safari pense qu'il est probable que ces images soient utilisées une deuxième fois, et donc qu'il les met en cache.

2

Les navigateurs sont connus pour les fuites de mémoire. Il semble que le problème se produit lorsque la page est en cours d'exécution pendant une longue période. Que diriez-vous d'actualiser la page avant qu'elle ne manque de mémoire?

window.setTimeout("location.reload()",1000*60*60);//refresh in an hour 
+3

Peut être modifié, qu'il ne rafraîchit que si l'utilisateur n'a rien fait depuis 5 minutes environ. –

0

Comme je l'ai récemment découvert, il existe un bug dans Firefox qui provoque des fuites de balises IMG orphelines.

Cela peut être contourné en déplaçant les images CSS:

if(number_of_things_seen > 10) { 
    $('#shots li:last-child').remove(); 
} 

$('<li><div style="background-image: url(\'' + p.ProductImageSmall + 
    '\'); background-repeat: no-repeat; background-position: center; '+ 
    ' width: 20px; height: 20px"></div></li>').prependTo('#shots'); 

Vérifiez si cela résout votre fuite de mémoire.