找到分离的DOM树内存泄漏

时间:2014-01-20 05:10:08

标签: javascript html google-chrome memory-leaks

我在主要使用Knockout构建的非常大的单页Web应用程序中诊断分离的DOM树内存泄漏时遇到了问题。

我已经调整了应用程序,将虚拟FooBar对象附加到特定的HTML按钮元素,当用户移动到应用程序的不同“页面”时,该元素应该被垃圾收集。使用Chrome的堆快照功能,我可以看到旧的FooBar实例(应该已经过GC)仍然可以从(大)分离的HTMLButtonElement中找到DOM树。

通过保留树面板跟踪引用,我跟踪链接从GC根目录减少距离。但是,在某些时候,我的搜索在与根的节点距离4处达到了死胡同(在这种情况下)!保留树根本不报告对此节点的引用,但不知何故知道它是GC根目录的四个步骤。

以下是保留树的一部分让我感到困惑(右边的数字是距离根部的距离):

v foobar in HTMLButtonElement                                  10
  v [4928] in Detached DOM tree / 5643 entries                  9
    v native in HTMLOptionElement                               8
      v [0] in Array                                            7
        v mappedNodes                                           6
          v [870] in Array                                      5
            v itemsToProcess in system / Context                4
                context in function itemMovedOrRetained()
                context in function callCallback()

保留树不会在距离3或以上显示参考。

任何人都可以向我解释这个吗?我希望我能够跟随参考链回到JavaScript应用程序代码中令人讨厌的部分 - 但这让我受阻了!

1 个答案:

答案 0 :(得分:13)

首先 - 不要使用delete作为建议的评论之一。设置对null的引用是处理事物的正确方法。 delete打破了隐藏的类"。要自己查看,请从https://github.com/naugtur/js-memory-demo

运行我的示例

Rafe,您在分析器中看到的内容通常很难理解。你在这里发布的这个位看起来很奇怪,可能是你的应用程序之外的一个bug或内存泄漏(浏览器泄漏),但是如果没有运行你的应用程序,很难说。保留树在函数的上下文中结束,并且可以通过对该函数的引用或共享上下文的某个其他函数来保留。对于探查器来说,正确地可视化它可能太复杂了。

我可以帮助您查明问题。

首先,转到devtools中的Timeline选项卡,然后使用它来观察泄漏发生的那一刻。仅选择内存分配并开始录制。浏览一下您希望泄漏的场景。保持蓝色的条纹是泄漏。您可以在时间轴中选择它们的周围环境,并专注于它们的保留树。分离的dom树中最有趣的元素是红色的 - 它们是从外部引用的。其余的保留,因为引用了树中的任何元素,它引用了其他所有元素(x.parentNode

如果您需要更多详细信息,可以在探查器中拍摄多个快照,以便在泄漏原因之前和之后获得快照(您在时间轴中找到了快照 - 您现在知道导致它的确切操作) 。然后,您可以比较分析器中的那些 - 那里有一个"比较"视图。这比其他人更容易理解。

您还可以从分析器中保存堆快照并在线发布,因此我们可以看看。左侧列表中的每个都有一个保存链接。


分析内存很难,实际上需要一些练习和对工具的理解。 你可以从我的演讲中练习一些例子:

http://naugtur.pl/pres/mem.html#/5/2

但是使用内存分析器的真正完整指南是这个doc:

https://developer.chrome.com/devtools/docs/javascript-memory-profiling#looking_up_color_coding

更新了链接: https://developers.google.com/web/tools/profile-performance/memory-problems/memory-diagnosis