在试图理解为什么我的一些 Web 应用程序的对象被 Chrome 保留在内存中之后,我想我可能已经把它缩小到MediaRecorder
浏览器保留对象的情况,即使应用程序已经放弃了对它的所有引用,显式和隐含的。
请注意以下重现该问题的最小示例:
new MediaRecorder(new MediaStream())
在评估了上述表达式之后——MediaRecorder
创建的对象没有分配给它的引用(变量或属性)——我使用 Chrome 和 Chromium 中的“内存”选项卡分析了堆使用情况,并且该MediaRecorder
对象在堆上的存在是'不是瞬态的——只要我想在堆上定位它,对象就在那里。它不会消失。
为什么保留?使用类似的普通类进行测试——例如,Object
评估的行为符合预期——垃圾收集最终会收集匿名对象。new Object()
但不是这样MediaRecorder
。这对我来说闻起来非常像虫子。
相比之下,FirefoxMediaRecorder
在适当的时候释放对象,当然考虑到垃圾收集,至少在我执行上面的语句之后它甚至不在堆上,而不是在我拍摄它的快照时。
媒体记录器对象没有被任何东西引用,并且应该具有它可能拥有的最短生命周期,但它在我在控制台被清除后拍摄的快照中存在于内存中(Chrome 开发者工具背后的开发人员建议在之前清除控制台拍摄堆快照,因为前者可能会保留原本会被释放的对象)。
我在类中找不到任何可以MediaRecorder
向我表明可以将其与流分离或以其他方式“关闭”它的方法。没有确保没有明显或不那么明显(例如通过事件侦听器)对它的引用,我只能希望匿名对象不会被保留,而这样的对象通常不会被保留,但MediaRecorder
对象似乎是. 可以这么说,似乎没有任何杠杆可以让我拉动处理一个。
您可以在下面的屏幕截图中看到,保留媒体记录器的对象并不完全是我的脚本的一部分,它们似乎与某些内部浏览器状态有关:
在“构造函数”列中选择的对象旁边的窗口图标具有工具提示“用户对象 [is] 可从窗口访问”。上面的代码片段是我在选项卡中运行的唯一代码,为什么对象会“从窗口可访问”,如果是,它肯定不能是我管理的任何引用?
那么为什么要保留对象呢?这里更大的问题是,如果我的应用程序启动许多记录并为每个记录创建一个新的媒体记录器对象,这些对象将不断堆积在内存中,这实际上是内存泄漏的情况。
就像我说的,我在 Firefox 62.0.2 中运行了相同的语句,并且行为与我预期的一样——MediaRecorder
我创建的单个对象似乎超出了范围(因为它应该没有引用它)创建后不久。
(Chrome 版本 69.0.3497.100,Windows 10 上的 x64)