我开发了一个扩展程序,用于拦截Web请求,获取Web请求所源自的HTML并对其进行处理。我已经使用DOMParser解析HTML,并且我意识到DOMParser会导致大量内存泄漏问题,最终导致chrome扩展崩溃。
这是导致问题的代码。 https://gist.github.com/uche1/20929b6ece7d647250828c63e4a2ffd4
我在chrome扩展程序拦截请求时记录了下来,我注意到当DOMParser.parseFromString方法被调用时,创建了更多的未破坏的节点和文档。
Dev工具截图 https://i.imgur.com/pMY50kR.png
我看了看chrome上的任务管理器,发现它具有巨大的内存占用,并且不会随着时间的推移而减少(因为垃圾收集会在一段时间后启动)。当内存占用空间太大时,扩展程序崩溃。
任务管理器内存占用量屏幕截图 https://i.imgur.com/c8fLWCy.png
我在堆的屏幕截图之前和之后都做了一些操作,我可以看到问题似乎是由于分配的HTMLDocuments引起的,而这些HTMLDocuments并没有被垃圾收集。
快照(之前) https://i.imgur.com/Rg2CRi6.png
快照(之后) https://i.imgur.com/UQgLuT1.png
我想了解为什么DOMParser导致了此类内存问题,为什么垃圾回收器未对其进行清理以及解决该问题的方法。
谢谢
答案 0 :(得分:1)
您基本上是在内存中复制整个DOM,然后再也不释放内存。
我们在客户端应用程序中避免了这个问题,因为当我们离开时,该页面上脚本所使用的内存将被恢复。
在后台脚本中,这不会发生,现在是您的责任。
使用完毕,请将parser
和document
都设置为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);
答案 1 :(得分:0)
我已经解决了问题。看来问题出在这是因为DOMParser类出于某种原因在内存中保留了它解析的HTML文档的引用,但没有释放它。由于我的扩展程序是在后台运行的Chrome扩展程序,因此会夸大此问题。
解决方案是使用另一种解析HTML文档的方法
let parseHtml = (html) => {
let template = document.createElement('template');
template.innerHTML = html;
return template;
}
这有助于解决问题。