【发布时间】:2014-02-09 04:31:42
【问题描述】:
我在诊断一个主要使用 Knockout 构建的非常大的单页 Web 应用程序中的分离 DOM 树内存泄漏时遇到了问题。
我对应用程序进行了调整,以将虚拟 FooBar 对象附加到特定的 HTML 按钮元素,当用户移动到应用程序的不同“页面”时,该元素应该被垃圾收集。使用 Chrome 的 堆快照 功能,我可以看到旧的 FooBar 实例(应该已经被 GC'ed)仍然可以从它的 HTMLButtonElement 在(大)分离的 DOM 树中访问。
通过retaining tree面板跟踪引用,我跟随从 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 应用程序代码的违规部分——但这阻碍了我!
【问题讨论】:
-
你能分享一些代码,特别是这个元素的创建位置和处理位置吗?
-
恐怕代码是专有的且庞大的;我还没有机会尝试在小范围内复制它。这里真正的问题是为什么 Chrome 堆分析器应该报告类似上面的东西,它不会在根部触底(这怎么可能?!)。
-
在删除
DOM元素之前,您必须删除属性foobar( 和delete;delete button.foobar并确保没有剩余的事件侦听器。 -
我不认为这是一个错误。目前,我正在使用我自己的框架和 DOJO 开发一个巨大的 SPA。内存泄漏也是一个大问题。由于我没有适当地破坏连接(事件侦听器)并且我正在引用其他对象(外部范围),因此创建的内存泄漏最多。将我的“正常”对象更改为模块模式后,我的泄漏消失了。总结;您能否发布代码如何使用
foobar属性创建按钮? -
@Rafe 但是我们应该如何帮助你呢?解决方案已经给出:您仍然拥有对该对象的引用。 GC 正在计算对一个对象的剩余引用。如果它变为 0,则该对象将被垃圾收集。否则,当有可能再次调用一个对象时,总会有一个引用。内存泄漏有很多种:闭包、循环引用、.. 如果没有提供代码,我们只能向您解释理论。早些时候,我试图解决一个巨大的应用程序(超过 1GB JS)中的内存泄漏,
标签: javascript html google-chrome memory-leaks