Javascript + IMG标签=内存泄漏。有一个更好的方法吗?

时间:2008-12-03 06:23:56

标签: javascript jquery html ajax browser

我有一个网页,使用jquery接收一些产品信息,因为人们正在查看事物,然后显示最后看到的产品图片。这是一个jquery AJAX回调,看起来非常像这样:

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

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

但是,它似乎泄漏了相当多的内存。在视觉上,它做的是正确的,但足迹无限增长。

Safari的DOM检查器显示DOM是我期望的那样,但它似乎保持对它所显示的每个图像的引用(如this screenshot中所见,以防有人感兴趣)。

我添加了

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

删除声明没有明显效果。

是否有必要让浏览器发布一些这样的东西?

8 个答案:

答案 0 :(得分:2)

浏览器因内存泄漏而臭名昭着。听起来好像页面长时间运行时会出现问题。如何在内存不足之前刷新页面?

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

答案 1 :(得分:1)

你能尝试改变最后一个孩子的src,看看是否有所作为? 然后,您可以将该元素移动为第一个子元素

//not tested

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

答案 2 :(得分:1)

来自Mozilla Developer Center on removeChild()

  

删除的子节点仍然存在于内存中,但不再是DOM的一部分。您可以通过oldChild对象引用在代码中稍后重用已删除的节点。

这是关键 - 重用已删除的孩子,而不是重复制作新孩子。

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

答案 3 :(得分:1)

足迹真的有问题吗?

我怀疑只要您停留在同一个网站上,Safari就会缓存所有图像,而您无能为力。如果幸运的话,Safari会在达到某些限制后释放不需要的对象。

这种行为的原因是,Safari认为这些图像可能是第二次使用,因此它会缓存它们。

答案 4 :(得分:0)

你有多久观察到这种“无限增长”?垃圾收集器的某些实现不一定能够如此快地将内存返回给操作系统。你可以将你想要做的事情提炼成一个真正的简单测试(例如,反复设置图像的src)没有ajax或回调吗?你/你可以尝试使用其他浏览器吗?

答案 5 :(得分:0)

好的我为此构建了一个测试工具,它随机抓取一个新图像并使用我的替换src代码

请参阅http://pastebin.me/4936458820c43

答案 6 :(得分:0)

达斯汀, 似乎我的代码中的insertBefore语句导致了一些问题。如果你看到这个更进一步的测试用例,即使我正在清空最后一个子节点并插入一个新的dom片段,内存使用仍保持静态。比上次尝试表现更好。

http://pastebin.me/4936519fea2cf

答案 7 :(得分:0)

正如我最近发现的,Firefox中存在一个导致孤立的IMG标记泄露的错误。

这可以通过将图像移动到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');

检查这是否能解决您的内存泄漏问题。