33

我对 google chrome(版本 20.0.1132.47,Ubuntu 11.04 64bit)中的垃圾收集有疑问。

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

看看下面的截图 显示仅由“bound_this”引用的实例(子)的堆转储屏幕截图

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

我正在使用映射到 chrome 的“native_bind”函数的underscore.js 的“bindAll”实用程序函数( underscore.js#bindAll )(bound_this 上的ECMA Script wiki

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

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

更新 2:
按照 Esailijas 提示提供一个 jsfiddle 片段,我创建了一个(http://jsfiddle.net/8gSTR/1/)来模仿我基本上在做的事情。不幸的是,运行这个小提琴并没有显示我在我的应用程序中遇到的不当行为。尽管来自 window.o 数组的引用使实例保持活动状态,但在仍然引用“a”实例时进行的堆转储看起来有点相似: 上面提到的 jsfiddle 执行期间进行的堆转储

由于在我的情况下缺少这样的参考(屏幕截图 1),我不知道是什么让 chrome 无法释放这些实例......

更新 3:
遵循 loislos 的建议以启用隐藏属性。结果(其中一个分支展开)可以在下面的屏幕截图中看到,但它不会让我更进一步。 启用了隐藏属性的堆转储

4

3 回答 3

4

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

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

即使您使用 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;博士; 使用 IE 11 检测泄漏。

于 2014-03-05T13:04:46.143 回答
1

您是否使用开发人员工具触发了“强制 GC”?如果是这种情况并且对象持续存在,那么上述研究是有价值的。

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

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

可能只是因为您没有达到触发年轻代 GC 所需的阈值,或者对象已被老一代使用,但从未触发过老一代 GC。

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

于 2013-08-08T16:04:51.543 回答
1

我在EcmaScript中提到了这个,这个术语将这个与类“绑定”,

类方法具有“绑定 this”,其中方法体中的 this 始终绑定到从中提取方法的类实例,而不管这个参数实际传递给方法的是什么(方法的 this 参数被忽略) .

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

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

然后对于任何对象,脚本是有界的,在类/对象存在之前它不会调用垃圾,因为这个函数与同一个对象绑定..它只会在其父对象(它所使用的对象/类)之后进行垃圾收集是有界的)范围结束。

现在,如果任务完成时的循环引用它将结束,>>这就像递归的概念(注意它的概念,不一样)..所以结束将从最后一次调用开始..反过来..最里面的电话(最新电话)将首先被释放..等等

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

我希望这会解释..

于 2013-07-16T05:17:14.197 回答