You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js Socket.io适配器页面刷新重复触发join-room事件致内存泄漏警告

Socket.io 适配器"join-room"监听器内存泄漏问题解决

问题现象

每次客户端刷新页面时,Socket.io适配器的join-room事件监听器会额外触发多次实例,日志顺序为:客户端断开连接 → 多次join-room事件 → 连接事件,最终收到警告:

(node:863) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 join-room listeners added to [Adapter]. Use emitter.setMaxListeners() to increase limit (Use 'node --trace-warnings ...' to show where the warning was created)

日志详情

socket.io: User connected:  F3N09wOefsqpNc32AAAB
socket a-wXTgd4OUrCWv7DAAAD has joined room a-wXTgd4OUrCWv7DAAAD
socket.io: User connected:  a-wXTgd4OUrCWv7DAAAD
socket.io: User disconnected:  F3N09wOefsqpNc32AAAB
socket DEkkVVUnGoP9c4kzAAAH has joined room DEkkVVUnGoP9c4kzAAAH
socket DEkkVVUnGoP9c4kzAAAH has joined room DEkkVVUnGoP9c4kzAAAH
socket.io: User connected:  DEkkVVUnGoP9c4kzAAAH
socket.io: User disconnected:  DEkkVVUnGoP9c4kzAAAH
socket 6jYs2BF3iM-PR67RAAAJ has joined room 6jYs2BF3iM-PR67RAAAJ
socket 6jYs2BF3iM-PR67RAAAJ has joined room 6jYs2BF3iM-PR67RAAAJ
socket 6jYs2BF3iM-PR67RAAAJ has joined room 6jYs2BF3iM-PR67RAAAJ
socket.io: User connected:  6jYs2BF3iM-PR67RAAAJ
...

socket.io: User connected:  Ed2xrTrQsJuXQJdAAAAT
socket.io: User disconnected:  Ed2xrTrQsJuXQJdAAAAT
socket WXglcjwFryvQMgMNAAAV has joined room WXglcjwFryvQMgMNAAAV
socket WXglcjwFryvQMgMNAAAV has joined room WXglcjwFryvQMgMNAAAV
socket WXglcjwFryvQMgMNAAAV has joined room WXglcjwFryvQMgMNAAAV
socket WXglcjwFryvQMgMNAAAV has joined room WXglcjwFryvQMgMNAAAV
socket WXglcjwFryvQMgMNAAAV has joined room WXglcjwFryvQMgMNAAAV
socket WXglcjwFryvQMgMNAAAV has joined room WXglcjwFryvQMgMNAAAV
socket WXglcjwFryvQMgMNAAAV has joined room WXglcjwFryvQMgMNAAAV
socket WXglcjwFryvQMgMNAAAV has joined room WXglcjwFryvQMgMNAAAV
socket WXglcjwFryvQMgMNAAAV has joined room WXglcjwFryvQMgMNAAAV
socket.io: User connected:  WXglcjwFryvQMgMNAAAV
(node:863) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 join-room listeners added to [Adapter]. Use emitter.setMaxListeners() to increase limit
(Use `node --trace-warnings ...` to show where the warning was created)

问题根源

你的代码把join-room事件监听器绑定在了io.on('connection')回调内部:

io.on('connection', socket => {
  // ...其他代码
  io.of("/").adapter.on("join-room", (room, id) => {
    console.log(`socket ${id} has joined room ${room}`);
  });
  // ...其他代码
});

每有一个客户端建立连接,就会新增一个join-room监听器。客户端刷新页面等于重复断开重连,监听器数量不断累积,超过Node.js默认的10个监听器上限后,就会触发内存泄漏警告。同时每次join-room事件触发时,所有已绑定的监听器都会执行,导致日志重复输出多次相同内容。

解决方案

把join-room监听器移到io.on('connection')回调外部,只绑定一次:

修改后的代码

const express = require('express')();
const cors = require('cors');
const { createServer } = require('http');
const { instrument } = require("@socket.io/admin-ui");
const { generateRoomId } = require('./utils');

const httpServer = createServer();
const io = require('socket.io')(httpServer, {
  cors: {
    origin: ["https://example.com", "https://admin.socket.io"],
    credentials: true
  }
});

// 把join-room监听器移到connection回调外面,只绑定一次
io.of("/").adapter.on("join-room", (room, id) => {
  console.log(`socket ${id} has joined room ${room}`);
});

io.on('connection', socket => {
  console.log("socket.io: User connected: ", socket.id);

  socket.on('newGame', () => {
    let roomId = generateRoomId(8);

    socket.join(roomId);
    socket.emit('joined', roomId);
  });

  socket.on('joinGame', (roomId) => {
    socket.join(roomId);
    socket.emit('joined', roomId);
  });

  socket.on("disconnect", () => {
    console.log("socket.io: User disconnected: ", socket.id);
  });
});

instrument(io, {
  auth: false
});

httpServer.listen(process.env.PORT || 3030);

修改效果

修改后,join-room监听器只会在服务器启动时绑定一次,不会随客户端连接数量增加而累积,彻底解决内存泄漏警告问题,同时每次socket加入房间时,日志只会输出一次对应信息。

内容的提问来源于stack exchange,提问作者Ryan Dantzler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 12:15:49