Node.js HTTP 模块的内存泄露问题
很久没有逛社区了,晚上回来看了一下最近的情况,突然看到一个内存泄露问题,作为一个 APM 开发者,自然想分析其中的原因。
问题
下面介绍一下具体的问题。看一下 demo。
const http = require('http')
async function main () {
let i = 0
while (true) {
if (i % 100 === 0) {
global.gc()
}
if (i % 10000 === 0) {
console.log(process.memoryUsage().heapUsed)
}
http.createServer((req, res) => {})
i
}
}
main()
Node.js v20.3.1 下执行上面代码(node --expose-gc demo.js)输出如下。
2681120
11409488
19632792
28038016
36438104
可以看到内存不断在增长。下面来分析这个问题。
分析
const http = require('http');
const v8 = require('v8');
for (i = 0; i < 1000; i ) {
http.createServer((req, res) => {});
}
v8.writeHeapSnapshot('memory-leaky.heapsnapshot');
采集的快照如下。
可以看到,Server 对象没有被释放。看一下是谁引用了它。
是定时器引用了 Server 对象,我们看一下定时器对象又是被谁引用了。
有一个关键的变量 connectionsCheckingInterval,到 Node.js 源码里看一下,最终发现是 Server 初始化时创建的。
function Server(options, requestListener) {
setupConnectionsTracking(this);
}
function setupConnectionsTracking(server) {
server[kConnectionsCheckingInterval] = setInterval(checkConnections.bind(server), server.connectionsCheckingInterval).unref();
}
可以看到 checkConnections.bind 返回的匿名函数持有了 Server,而匿名函数又被 setInterval 持有了,所以导致 Server 对象无法释放。
修复
那么如何修复这个问题呢?修复这个问题,首先需要了解 setupConnectionsTracking 是做什么的,逻辑如下。
function checkConnections() {
if (this.headersTimeout === 0 && this.requestTimeout === 0) {
return;
}
const expired = this[kConnections].expired(this.headersTimeout, this.requestTimeout);
for (let i = 0; i < expired.length; i ) {
const socket = expired[i].socket;
if (socket) {
onRequestTimeout(socket);
}
}
}
可以看到,setupConnectionsTracking 是追踪连接超时,回到我们的测试例子中可以发现,我们并没有执行 listen,也就是说,Server 对象并不会处理连接,那么也就没有连接需要追踪,所以修复方式就是把调用 setupConnectionsTracking 的时机延迟到 listen 成功时,修复代码大致如下。
function Server(options, requestListener) {
this.on('listening', () => {
setupConnectionsTracking(this);
});
}
修改源码重新编译后测试结果如下。
3653552
4002680
3753400
3762976
3773088
可以看到内存已经不会增长了,采集快照也可以看到不会再存在大量 Server 对象。
总结
这个例子虽然看起来有点不常见,用法也很怪异,但是从侧面说明了虽然 JS 自带 GC,但是因为逻辑 / 引用关系复杂,还是很容易出现内存泄露问题,所以写代码时还是需要注意,具体的 issue 可以参考 https://github.com/nodejs/node/issues/48604。
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhggaehk
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01