32

我有一个关于谷歌浏览器中垃圾收集的问题(版本20.0.1132.47,Ubuntu 11.04 64位)。'bound_this'引用的实例只是不被垃圾收集

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

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

实例“孩子@ 610739”被引用看看只能通过属于子实例本身的函数的'bound_this'实例。所以据我的理解,子实例应该被垃圾收集,因为唯一保留它的其他引用是子实例本身(通过'bound_this'函数)。

我使用映射到镀铬的‘native_bind’功能underscore.js' bindAll“效用函数(underscore.js#bindAll)(ECMA Script wiki on bound_this

我失去了一些东西在这里很明显,如果是这样,可能有人解释什么让这些实例活着?

UPDATE:
在我chrominium测试同一个应用程序的同时(18.0.1025.168(开发版本的Linux 134367)的Ubuntu 11.10),它不显示这些未实例..

更新2:
继Esailijas暗示提供一个jsfiddle片段,我创建了一个(http://jsfiddle.net/8gSTR/1/),模仿我基本上正在做的事情。不幸的是,运行这个小提琴不会显示我在应用程序中遇到的不当行为。而“a'结构实例仍然被引用采取堆转储虽然看起来有点类似,尽管从window.o数组这使活着的情况下,参考: Heap-dump taken during execution of jsfiddle mentioned above

这样的引用在我的情况是缺少(屏幕截图1)我不知道是什么让Chrome自由释放这些实例...

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

+0

在这里没有看到这个http://jsfiddle.net/uGX22/3/。起初他们在那里(堆取17。32mb,有60000次关闭),我等了几分钟,拍了一张新快照,堆又回到了6mb,关闭消失了。你能修改我的jsfiddle来重现这个吗? – Esailija 2012-07-20 09:19:14

+0

你能告诉我们你创建这种情况的代码吗?我真的从调试器的屏幕截图中看不到它。 – Bergi 2012-07-20 09:23:09

+0

我会尝试创建一个小片段来重现问题。我创建这种情况的代码是一个相当大的SPA的一部分,因此提取起来并不容易。 – 2012-07-20 09:28:16

回答

3

你怀疑这不是一个实际的内存泄漏,而是铬的怪异是正确的。

我最近遇到同样的问题。 IE11不会显示this.func = _.bind(this.func,this)作为内存泄漏,而即使在您按下收集垃圾按钮100次之后,Chrome也会发生内存泄漏。

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

一个简单的方法来证明它实际上不是铬中的泄漏,这是一个小问题,它是浏览器的一个主要问题,并迫使引擎采取行动。

在具有分配给它的绑定函数分配这样一个新的属性的实例:

target.WhyAmILeaking =新阵列(2亿)。加入(“YOURNOT”);

使用chrome执行三种快照技术,您会看到堆中的字符串出现在214mb左右。再次做任何有建设性的行动(第二个快照),你会看到堆积为423mb或停留在214mb。如果它保持不变,就证明原始214mb已被收集。如果它不保留你的破坏性行动(第三张快照),它会回到214mb也证明原始收集。

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

哦,另一组跨越完全相同的情况下跑了可怜的灵魂的:https://github.com/jashkenas/backbone/issues/2269#issuecomment-13610969

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

1

我在EcmaScript称为此,该术语“束缚,这”与类,

类方法具有“绑定这个”,其中该在该方法中体总是绑定到类实例从中方法被提取出来,而不管这个参数实际上传递给方法(该方法的这个参数被忽略)。

现在,这里在你的例子有鉴于所以没有示例脚本不能具体质疑,

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

然后什么都反对,类脚本是有界的,它不会调用垃圾,直到类/对象存在,因为这个函数被相同的对象绑定在一起。它只会在它的父对象(与它绑定的对象/类)作用域结束后才会收集垃圾。

现在,如果循环引用任务完成时它会结束,>>这个工作像递归概念(介意它的概念,不一样)..所以结束将从最后一次调用开始.. in反向..最内线电话(最新通话)将首先发布..等等

该代码必须是越野车,因为他们不得绑定和定义函数和每次重用..但如果他们绑定,然后还它应该工作正常,并且不应该泄漏,直到足迹超出内存池的浏览器限制。

我希望这将解释..

1

你是否触发“强制气相色谱法”使用的开发工具?如果是这种情况,然后对象持续存在,那么上述研究就很有价值。

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

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

这可能仅仅是你没有达到所需的阈值触发年轻一代GC,或该对象已被终身教授的老一代,但一个老一代GC从未被触发。

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