灏天阁

使用 iframe 发生内存泄漏

· Yin灏

iframe 定义

依据 MDN(HTML(超文本标记语言) | MDN (mozilla.org))的定义:

HTML 内联框架元素 (<iframe>)   表示嵌套的browsing context。它能够将另一个 HTML 页面嵌入到当前页面中。

每个嵌入的浏览上下文(embedded browsing context)都有自己的会话历史记录 (session history)DOM 树。包含嵌入内容的浏览上下文称为父级浏览上下文。顶级浏览上下文(没有父级)通常是由  Window  对象表示的浏览器窗口。

iframe 使用示例

<iframe
  id="iframe1"
  src="https://cn.bing.com/"
  frameborder="0"
  width="100%"
  height="300"
></iframe>

使用 iframe 的内存泄漏

在使用 iframe 时发现切换 iframe 页面 src 或者是关闭 iframe 页面时,iframe 相关的内存资源几乎没有释放掉。

切换 iframe 页面的内存泄漏

初始浏览器界面如下:

image.png

相关代码如下:

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div>
      <iframe
        id="iframe1"
        src="https://www.bing.com/"
        frameborder="0"
        width="500"
        height="400"
      ></iframe>
    </div>
    <button onclick="changeIframeSrc()">切换</button>
  </body>
  <script>
    let num = 0;
    const arr = [
      "https://www.baidu.com/home",
      "https://zhidao.baidu.com/",
      "https://www.hao123.com/?src=from_pc",
    ];
    function changeIframeSrc() {
      const iframe = document.getElementById("iframe1");
      if (num === arr.length) {
        num = 0;
      }
      iframe.src = arr[num];
      console.log(111, iframe.src);
      num++;
    }
  </script>
</html>

初始任务管理器如下:

image.png

点击几次切换按钮时,查看 windows 系统的任务管理器,

image.png

在切换过程中产生了内存泄漏

解决步骤 1:

点击切换按钮时,在切换逻辑函数中,动态删除 iframe 和创建 iframe。

更改 changeIframeSrc 函数逻辑:

function changeIframeSrc() {
  const box = document.getElementById("iframe_box");
  const iframe = document.getElementById("iframe1");
  box.removeChild(iframe);
  //
  if (num === arr.length) {
    num = 0;
  }
  const iframeNew = document.createElement("iframe");
  iframeNew.src = arr[num];
  iframe.style = "width:500;height:400;";
  box.appendChild(iframeNew);
  num++;
}

初始任务管理器界面:

image.png

点击切换按钮几次,查看任务管理器:

image.png

发现还是有内存泄漏情况,接下来进行

解决步骤 2:

调用下文当中的 clearIframeFun 方法逻辑

<script>
  let num = 0;
  const arr = [
    "https://www.baidu.com/home",
    "https://zhidao.baidu.com/",
    "https://www.hao123.com/?src=from_pc",
  ];
  function changeIframeSrc() {
    const box = document.getElementsByClassName("iframe_box")[0];
    clearIframeFun("iframe1");
    //
    if (num === arr.length) {
      num = 0;
    }
    const iframeNew = document.createElement("iframe");
    iframeNew.id = "iframe1";
    iframeNew.src = arr[num];
    iframeNew.frameborder = "0";
    iframeNew.style = "width:500;height:400;";
    box.appendChild(iframeNew);
    num++;
  }
  function clearIframeFun(id) {
    let element = document.getElementById(id);
    element.src = "";
    element.contentWindow.document.write(""); // 清空iframe内容 element.contentWindow.document.clear()
    element.contentWindow.close(); // 避免iframe内存泄漏
    element.remove(); // 删除iframe
    document.body.removeChild(element);
  }
</script>

大致思路就是切换 iframe 时清除掉上一个 ifarme 的相关资源。

关闭 iframe 页面的内存泄漏

开始浏览器界面是这样的,打开按钮出现 iframe 界面,关闭按钮去掉 iframe 界面:

image.png

以下资源占用情况是使用的 windows 的任务管理器查看的。

当点击关闭按钮没有调用 clearIframeFun 函数时,内存占用情况如下:

image.png

可见谷歌浏览器目前有 9 个进程,占用总的内存大概 200M,下面点击show iframe page按钮,浏览器界面如下:

image.png

查看任务管理器:

image.png

点击关闭按钮,查看任务管理器:

image.png

可见内存占用变少,主要原因是 iframe 元素去掉了,v-if (vue3)的作用:

<div class="iframe_box" v-if="iframeVisible">
  <iframe
    id="iframe1"
    src="https://cn.bing.com/"
    frameborder="0"
    width="800"
    height="500"
  ></iframe>
</div>

接下来使用下面的代码去掉内存占用:

const handleClose = () => {
  iframeVisible.value = false;
  let iframe: any = document.getElementById("iframe1");
  clearIframeFun(iframe);
};
const clearIframeFun = (id: any) => {
  let element: any = document.getElementById(id);
  element.src = "";
  element.contentWindow.document.write(""); // 清空iframe内容
  element.contentWindow.document.clear();
  element.contentWindow.close(); // 避免iframe内存泄漏
  element.remove(); // 删除iframe
  document.body.removeChild(element);
};

点击 show iframe page 按钮,任务管理器如下:

image.png

有 10 个进程,内存占用将近 300M。

点击 close iframe page 按钮,如下:

image.png

进程变成了 9 个,内存占用将近 200M,性能提升比较大。

一个 iframe 页面对应一个进程。

- Book Lists -