动态更改iframe的src会导致内存泄漏。

4
我正在测试在Vue模板内更改<iframe>src属性的动态变化。在测试中,我每秒更改一次src。几分钟后,我的可用内存使用率达到了88%,最终计算机崩溃了。我在一个Windows 10机器上进行了此测试,该机器有32 GB内存和Firefox浏览器。
然而,在Raspberry Pi 4(4GB)上使用chromium-browser时,我首先注意到了内存问题。我不断地切换多个vue组件(如幻灯片)。其中一些也有iframes。就像上面的测试一样,内存泄漏了(虽然不是很快但在几天内),chromium-browser标签崩溃并显示“他死了吉姆”的笑脸。
以下是测试代码:
<template>
  <div id="app">
    <iframe :src="src" />
    {{ count }}
    {{ src }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      src : "",
      source : [
        "https://example.com/embeddedcontent/1",
        "https://example.com/embeddedcontent/2",
        "https://example.com/embeddedcontent/3",
        "https://example.com/embeddedcontent/4"
      ],
      count : 0,
      interval : null
    }
  },
  mounted() {
    const interval = setInterval(() => {
      this.src = this.source[ this.count % this.source.length ];
      this.count = this.count + 1
    }, 2000);
    this.interval = interval;
  },
  beforeDestroy() {
    clearInterval(this.interval);
  }
}
</script>

事实

  • 在不同的系统和浏览器上(Win10/FirefoxRaspbian/chromium-browser)注意到相同的内存泄漏。
  • 在Vue的开发(HMR)和生产版本中注意到相同的内存泄漏。虽然是独立的Vue应用程序。
  • iframe的内容对我来说是未知的,因为src属性可以设置为任何URL。

有什么方法可以防止这种情况发生吗?

目前,我只考虑过每隔几分钟刷新浏览器选项卡。这种方法有点不太正式,因为它没有解决问题的根源。当我想在我的Vue应用程序中显示另一个网站的内容时,除了使用iframes之外,是否有其他替代方法?是否有一种方法可以清理整个iframe而不会留下任何东西?

更新2021/02/25

我现在也尝试了Edge浏览器,结果相同(随时间增长内存不断增加)。我还尝试了Firefox的私人模式,影响很小(内存增长但速度较慢)。比较了Vue示例的生产和开发版本,没有区别。我还尝试了一个纯电子应用程序,其中包含以下代码(没有Vue):

let interval = null;
let sources = [
  "https://hurtigruten.panomax.com/ms-roald-amundsen",
  "https://hurtigruten.panomax.com/ms-fridtjof-nansen",
  "https://rosenalp.panomax.com/",
  "https://alpbach.panomax.com/galtenberg",
];
let index = 0;
let count = 0;

function startTheInterval() {

  interval = setInterval(() => {
    
    index = count % sources.length;
    count = count + 1;
    document.getElementById('monitor').src = sources[index];

  },2000);

}

function clearTheInterval() {
  clearInterval(interval);
}

startTheInterval();

相同的结果,内存增加快速。
1个回答

2
首先,让我们来了解一下浏览器中iframe的工作原理 - 分离窗口内存泄漏
  1. 在调试内存泄漏时,请始终使用“隐身模式”-即浏览器不使用任何扩展程序的模式。扩展程序可能会保留对加载到iframe中的HTML的引用并保持该数据的活动状态。当我在Chrome中对您的示例进行分析时,只需切换到隐身模式就可以大大减少内存分配和保留...

  2. 不要使用Vue CLI/Webpack开发模式来调试内存泄漏。Webpack的热模块重新加载(HMR)可能会影响内存中保存的内容。请始终使用生产版本进行调试...

  3. 请注意,JS运行时(在本例中为V8)会收集有关正在执行的代码的一些元数据,并将其保存在JS堆中。看起来像内存泄漏的东西可能只是JS虚拟机元数据...

更新: 我在我的开发机器上(Ryzen 5 3600,32G内存,Win 10 x64)上使用您的示例(间隔为1秒而不是2秒)运行了一些测试-由serve-handler提供的生产构建加载到Firefox Developer Edition v86.0b9(64位)的私人窗口(因此没有任何扩展程序)

  1. 首先打开Dev工具并打开内存分析(启用Record call stacks选项)。在开始时记录一个快照,然后在大约40分钟后再记录一个快照。比较这些快照并没有显示任何JS堆分配增加。浏览器的私有字节(使用Sysinternals Process Explorer)显示增加了约60MB,但该内存在我关闭Dev工具时被清除,因此可以肯定它是Dev工具使用的内存。

  2. 同样的示例,现在没有打开Dev工具-运行了40分钟。再次没有任何内存增加...

因此,我的结论是没有与iframe或Vue本身相关的内存泄漏。如果您真的看到像“在几分钟内,我的可用内存使用了88%”这样的戏剧性情况,您应该检查自己的系统,特别是浏览器中安装的扩展程序...


很好的观点。但是我不确定我正在尝试调试内存泄漏,因为我已经知道iframe引起了它。iframe内部的内容(src)可能会有所不同,而且对我来说是未知的。此外,问题从开发到生产版本都存在。我将在我的问题中更新更多信息。我想我真正想要的是如何避免创建/销毁iframe导致内存泄漏。 - Pascal Lamers
我在我的问题中添加了一些更多的信息。是否还有其他重要信息缺失? - Pascal Lamers
你的更新很有趣,谢谢! - 我认为这与Vue无关。 但是我必须再次强调,我在两个非常不同的系统上(一个是使用chromium-browser的树莓派4,另一个是使用Firefox的Windows机器)使用iframe时遇到了内存泄漏问题。我将检查这两个系统是否涉及任何扩展程序,以确保安全。你所说的 serve-handler 是什么意思? - Pascal Lamers
1
是的,我理解这个问题 - 只是报告我自己的观察。serve-handler 是一个 Node 包,可以轻松创建本地 HTTP 服务器。我正在使用它在本地运行 Vue 生产构建... - Michal Levý
哦,我明白了!在我的特定情况下,我在 vue.config.js 中使用了 publicPath: "" 选项。使用这个选项,我能够直接在浏览器中打开 Vue 生产构建版本,而不需要通过 HTTP 服务。也许还有一些值得检查的差异。 - Pascal Lamers
有趣。我真的很好奇,使用HTTP而不是file:是否会有所不同... - Michal Levý

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接