【问题标题】:Javascript + IMG tags = memory leak. Is there a better way to do this?Javascript + IMG 标签 = 内存泄漏。有一个更好的方法吗?
【发布时间】:2008-12-03 06:23:56
【问题描述】:

我有一个网页,它使用 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();

对删除声明没有明显影响。

是否有必要让浏览器释放这些东西?

【问题讨论】:

  • 您找到泄漏了吗?如果你愿意,我会很感兴趣。
  • 没有。它仍然像疯了一样泄漏。我已经完成了一个不同版本的应用程序,它具有相当不同的显示机制,但我仍然看到图像泄漏。
  • 当你写一个测试用例时,比如说一个单一的 img 标签和一个 JavaScript 循环,它从一堆 URL 中替换它的 src 属性(没有 JS 框架,只是一个大的静态 URL 数组和一个三线路循环) - 它仍然泄漏吗?如果是这样,那你就不走运了,如果不是整个事情都可以解决。
  • 更多工作,但通过没有缓存标头的 php 脚本提供图像,而不是直接调用它们。

标签: javascript jquery html ajax browser


【解决方案1】:

浏览器因内存泄漏而臭名昭著。听起来问题发生在页面长时间运行时。在内存不足之前刷新页面怎么样?

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

【讨论】:

  • 可以修改,只有在用户5分钟左右没有做任何事情时才会刷新。
【解决方案2】:

您可以尝试更改 last-child 的 src 看看是否会有所不同吗? 然后,您可以将该元素移动为第一个子元素

//not tested

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

【讨论】:

  • 我喜欢这个建议导致的代码,但图像似乎仍然没有消失。
  • Dustin 当你说图像不会消失时,你能澄清一下吗?你的意思是它不交换图像?
  • 这很奇怪,因为 jquery 中的 remove 被优化以防止泄漏。也许是 xhr 对象的创建正在泄漏?
  • 在我显示图像之前,它的泄漏速度要慢得多——在我看到它超过 100MB 之前,它的更新速度要慢得多。
  • Dustin,您能否澄清一下更改图像 src 是否不起作用?
【解决方案3】:

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

【讨论】:

  • 这几乎就是 redsquare 让我做的事情。它有效,但不能防止泄漏。 ://
  • 如果你只是移动孩子而不接触src,它会不会长得一样?
  • 而且 - 你真的尝试过 not 为此使用 jQuery(例如,尝试仅使用 JS 的方法)吗?也许 jQuery 本身仍然以某种方式负责。
【解决方案4】:

足迹真的有问题吗?

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

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

【讨论】:

    【解决方案5】:

    您观察到这种“无限增长”有多久了?如果有的话,垃圾收集器的某些实现不一定会这么快地将内存归还给操作系统。你能把你想要做的事情提炼成一个真正简单的测试(例如,一遍又一遍地设置图像的 src)w/o ajax 或回调吗?你/你能用其他浏览器试试这个吗?

    【讨论】:

    • 我让它运行了几个小时并滚动了几千种产品。我看不出它曾经释放过任何东西。
    • 这可能发生在现实世界的用例中吗?
    • @redsquare 绝对是。这是可视化公司产品的使用情况。我希望他们整天把它搁置一旁。图片看起来很漂亮,但如果浏览器在繁忙的日子里崩溃,我可能不得不拉它们。
    • @Scott Safari 泄漏内存的速度比 firefox 慢,但我实际上并没有试图弄清楚 firefox 对内存做了什么。不过,我很确定是图像本身。
    【解决方案6】:

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

    http://pastebin.me/4936458820c43

    【讨论】:

    • 我没有看到 safari 中的图像数量在增长。我想这有点好。我认为这是 +1 xhr 理论。不过,我不太明白谁有 img 参考。
    • 也许我明天试试 irc,看看有没有人能告诉我你在做什么和我在做什么之间的区别。感谢您的帮助(到目前为止)。
    【解决方案7】:

    达斯汀, 我的代码中的 insertBefore 语句似乎导致了一些问题。如果您看到这个进一步的测试用例,即使我清空最后一个孩子并插入一个新的新 dom 片段,内存使用情况也会保持不变。比上次尝试的表现更好。

    http://pastebin.me/4936519fea2cf

    【讨论】:

      【解决方案8】:

      正如我最近发现的那样,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');
      

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

      【讨论】:

        猜你喜欢
        • 2016-12-04
        • 2017-05-16
        • 2012-12-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-13
        相关资源
        最近更新 更多