【问题标题】:DOM Parser Chrome extension memory leakDOM Parser Chrome 扩展内存泄漏
【发布时间】:2019-06-04 21:43:23
【问题描述】:

问题

我开发了一个扩展程序,它可以拦截 Web 请求、获取 Web 请求所源自的 HTML 并对其进行处理。我已经使用 DOMParser 解析 HTML,我意识到 DOMParser 会导致大量内存泄漏问题,最终导致 chrome 扩展崩溃。

这是导致问题的代码。 https://gist.github.com/uche1/20929b6ece7d647250828c63e4a2ffd4

我尝试过的

开发工具记录的性能

我在拦截请求时记录了 chrome 扩展,我注意到当调用 DOMParser.parseFromString 方法时,创建的节点和文档越多,但未被销毁。

开发工具截图 https://i.imgur.com/pMY50kR.png

任务管理器内存占用

我查看了 chrome 上的任务管理器,发现它的内存占用量很大,不会随着时间的推移而减少(因为垃圾收集应该在一段时间后开始)。当内存占用过大时,扩展程序崩溃。

任务管理器内存占用截图 https://i.imgur.com/c8fLWCy.png

堆快照

我在堆的屏幕截图之前和之后拍摄了一些,我可以看到问题似乎源于分配的 HTMLDocuments 没有被垃圾收集。

快照(之前) https://i.imgur.com/Rg2CRi6.png

快照(之后) https://i.imgur.com/UQgLuT1.png

预期结果

我想了解为什么 DOMParser 会导致此类内存问题,为什么垃圾收集器没有清理它以及如何解决它。

谢谢

【问题讨论】:

  • 这是全部代码吗?将 HTML 解析为 document 变量后,您不会对其执行任何操作吗?
  • @RandyCasburn 是的,解析后,我对文档不做任何事情。我试图将其设置为 null 以鼓励垃圾收集,但这不起作用。
  • 请看我的回答。
  • 然后将parser设置为null。

标签: javascript browser google-chrome-extension memory-leaks domparser


【解决方案1】:

我已经解决了这个问题。问题似乎是因为 DOMParser 类出于某种原因将它解析的 HTML 文档的引用保留在内存中并且没有释放它。因为我的扩展是在后台运行的 Chrome 扩展,所以夸大了这个问题。

解决方案是使用另一种解析 HTML 文档的方法

let parseHtml = (html) => {
    let template = document.createElement('template');
    template.innerHTML = html;
    return template; 
}

这有助于解决问题。

【讨论】:

    【解决方案2】:

    您基本上是在内存中复制整个 DOM,然后永远不会释放内存。

    我们在客户端应用程序中解决了这个问题,因为当我们离开时,该页面上的脚本使用的内存会被恢复。

    在后台脚本中,这不会发生,现在是您的责任。

    所以当你用完后将parserdocument 都设置为null

    chrome.webRequest.onCompleted.addListener(async request => {
        if (request.tabId !== -1) {
            let html = await getHtmlForTab(request.tabId);
            let parser = new DOMParser();
            let document = parser.parseFromString(html, "text/html");
            let title = document.querySelector("title").textContent;
            console.log(title);
            parser = null; // <----- DO THIS
            document = null; // <----- DO THIS
        }
    }, requestFilter);
    

    【讨论】:

    • 当我怀疑文档变量是问题时,这是我尝试的第一件事,但遗憾的是这并没有什么不同。
    • 你都试过了吗? parser & document
    • 我刚刚尝试将两者都设置为 null 并且仍然相同。内存没有得到释放
    • 内存分配是否显示该侦听器创建了该内存?堆快照是否显示此 DOM 已分离?
    • 是的,确实如此,查看堆快照,我可以看到每个已解析页面的 DOM 元素仍然存在。我不知道它们是否显示为被检测到。我不知道该怎么说。
    【解决方案3】:

    我无法指出 Chromium 中已确认的错误报告,但我们也受到内存泄漏的打击。如果您正在开发扩展程序,DOMParser 将在基于 Chromium 的浏览器的后台脚本中泄漏,但不会在 Firefox 上泄漏。

    我们无法获得此处提到的任何解决方法来解决泄漏,因此我们最终将原生 DOMParser 替换为 linkedom 库,它提供了一个插入式替换并在浏览器中工作(不仅在 NodeJs 中)。它解决了泄漏,因此您可能会考虑它,但是您需要注意一些方面:

    • 它不会泄漏,但它的初始内存占用比使用本机解析器要高
    • 性能很可能较慢(但我尚未对其进行基准测试)
    • 由其 HTML 解析器生成的 DOM 可能与 Firefox 或 Chrome 生成的略有不同。这种效果在损坏的 HTML 中最为明显,并且浏览器会尝试对其进行错误纠正。

    我们还首先尝试了jsdom,它试图以更高的代码库复杂性为代价与主流浏览器更加兼容。不幸的是,我们发现很难让 jsdom 在浏览器中运行(但在 NodeJs 上运行良好)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-12
      • 2018-05-30
      • 2019-07-16
      • 2018-05-19
      • 2015-11-23
      • 1970-01-01
      • 2014-03-10
      • 1970-01-01
      相关资源
      最近更新 更多