活动手柄
句柄是对开放资源(例如打开的文件、数据库连接或请求)的引用。为了理解为什么句柄应该处于关闭状态却可能处于活动状态,我给你一个简单的例子:
const http = require('http');
http.createServer((req, res) => {
if (req.url === '/secret-url') {
return; // nobody should have access to this part of our page!
}
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World!');
}).listen(3000);
这段代码有什么作用?它在端口上运行服务器3000
并返回一个Hello World
任何请求的消息,除了那些发送到“秘密 URL”的请求。但这段代码有一个问题。当我们遇到“秘密”if 子句时,我们永远不会关闭连接。这意味着客户端将根据需要保持连接打开。我们应该关闭连接。如果犯这个错误,活动句柄的数量将会增加,从而导致内存泄漏。
通常,内存泄漏更难检测,因为活动句柄可能从一个函数传递到另一个函数,从而很难跟踪哪段代码负责关闭连接。
活动句柄数量不断增加意味着什么?
如果您看到打开的句柄不断增加,则很可能您的代码中某处存在内存泄漏。就像示例中一样,您可能忘记关闭资源
如果您计划开发一个需要运行很长时间的脚本(例如 Web 服务器),那么内存泄漏尤其严重……
如何检查内存泄漏?
有多种技术可以检查内存泄漏。最简单的方法显然是密切关注记忆。 pm2 甚至内置了一个选项,可以在内存达到某个点时重新启动进程。有关此主题的更多信息,请查看本指南 https://marmelab.com/blog/2018/04/03/how-to-track-and-fix-memory-leak-with-nodejs.html.
这和傀儡师有什么关系?
两件事情。首先,请求非常便宜。即使 Node.js 服务器应用程序中存在内存泄漏,您也只会在几千个请求后才开始在内存中看到它。与此相反,木偶师是very昂贵的。打开 Chromium 浏览器将消耗 50 到 100 MB 的内存。因此,您应该确保您启动的每个浏览器都将被关闭。其次,正如另一个答案已经提到的那样,有一些对象(比如elementHandle https://github.com/GoogleChrome/puppeteer/blob/v1.15.0/docs/api.md#elementhandledispose)您需要手动处置以清除其资源。