'bound_this'引用的实例不是垃圾回收

时间:2012-07-20 09:13:33

标签: javascript google-chrome memory memory-leaks google-chrome-devtools

我对谷歌浏览器中的垃圾收集有疑问(版本20.0.1132.47,Ubuntu 11.04 64位)。

在比较堆转储和检查内存泄漏时,我发现了一些从未清理过的实例。通常这种行为可以追溯到程序员错误,但在这种情况下我很无能......

看一下下面的截图 Screenshot of heap-dump showing an instance (child) referenced only by 'bound_this'

实例'child @ 610739'仅由属于子实例本身的函数的'bound_this'实例引用。所以根据我的理解,子实例应该是垃圾收集的,因为保持它的唯一其他引用是子实例本身(通过'bound_this'函数)。

我正在使用下划线.js''bindAll'效用函数(underscore.js#bindAll)映射到chrome的{native_bind'函数(ECMA Script wiki on bound_this

我是否遗漏了一些明显的东西,如果是这样,有人可以解释是什么让这些实例保持活力吗?

更新:
与此同时,我在chrominium(18.0.1025.168(Developer Build 134367 Linux)Ubuntu 11.10)中测试了相同的应用程序,但没有显示这些悬空实例..

更新2:
在Esailijas提示提供一个jsfiddle片段之后,我创建了一个(http://jsfiddle.net/8gSTR/1/)来模仿我基本上正在做的事情。不幸的是,运行这个小提琴并没有表明我在申请中遇到的不当行为。尽管引用了window.o数组来保持实例存活,但仍然引用“a”实例时所采用的堆转储看起来有点类似。 Heap-dump taken during execution of jsfiddle mentioned above

因为在我的案例中缺少这样的引用(截图1)我不知道是什么阻止了chrome释放这些实例......

更新3:
跟随loislos建议启用隐藏属性。结果(扩展其中一个分支)可以在下面的屏幕截图中看到,但它不会让我更进一步。 Heap-dump with hidden properties enabled

3 个答案:

答案 0 :(得分:4)

您怀疑这不是实际的内存泄漏,但使用chrome的怪异是正确的。

我最近碰到了同样的问题。即使你按下收集垃圾按钮100次,IE11也不会显示this.func = _.bind(this.func,this)作为内存泄漏。

即使在使用jsflag废话运行chrome并显示底层垃圾收集器并调用gc 100次之后,它也会显示它。

一种简单的方法来证明它实际上并不是Chrome中的漏洞,这会导致一个小问题成为浏览器的一个主要问题并迫使引擎采取行动。

在分配了绑定函数的实例上,分配一个新属性,如下所示:

target.WhyAmILeaking = new Array(200000000).join(“YOURNOT”);

使用chrome执行三种快照技术,您将看到堆中存在的字符串大约为214mb。再做任何建设性行动(第二个快照),你会看到堆到423mb或保持在214mb。如果它已经完成,你已经证实已经收集了原来的214mb。如果它没有停留做你的破坏性行动(第三次快照),它将回到214mb,也证明收集的原件。

如果只是停留在423mb,你先生或女士有泄漏。

哦,另一群可怜的灵魂遇到了完全相同的情况:https://github.com/jashkenas/backbone/issues/2269#issuecomment-13610969

TL; DR;使用IE 11检测泄漏。

答案 1 :(得分:1)

我在EcmaScript中引用了这个词,这个术语“用这个词绑定”,

类方法已“绑定此”,其中方法体中的此方法始终绑定到从中提取方法的类实例,而不管此参数实际传递给方法的是什么(此参数为方法被忽略了。)

现在,在您的示例中,没有给出示例脚本,因此不能特定于问题,

我不得不说这不是泄漏..

然后用什么对象,类脚本是有界的,它不会调用垃圾,直到类/对象存在,因为这个函数与同一个对象有界..它只会在其父对象(对象/类)之后进行垃圾收集范围结束。

现在,如果任务完成时循环引用将结束,>>这就像Recursion的概念(记住它的概念,不一样)..所以结束将从最后一次调用开始..反向..最内部调用(最新调用)将首先释放..依此类推/ p>

代码必须是错误的,因为它们不能绑定和定义函数并且每次都重用..但是如果它们是绑定的话,它也应该正常工作并且不应该泄漏,直到占用空间超出内存池的浏览器限制。

我希望这会解释..

答案 2 :(得分:1)

您是否使用开发人员工具触发“强制GC”?如果是这种情况,然后对象仍然存在,那么上面的研究是有价值的。

如果您没有通过开发人员工具触发GC,那么请记住GC引擎的工作方式非常复杂,并且具有分代收集的概念(使用两代)。

http://www.html5rocks.com/en/tutorials/memory/effectivemanagement/#toc-v8-gc

可能只是你没有达到触发年轻一代GC所需的阈值,或者说这些对象已经被老一代所用,但是老一代的GC从未被触发过。

不幸的是,开发人员工具似乎没有显示GC的哪一代。