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