我正在评估Node.js,以便在Java Web App上替换我当前的推送功能。我写了一个简单的长轮询服务器,它像客户端和Java后端之间的中介。客户端发出订阅请求,然后Java服务器可以通过调用Node.js来通知订阅的客户端。到目前为止似乎工作正常,但我收到以下消息,指出内存泄漏:
(node) warning: possible EventEmitter memory leak detected. 11 listeners added.
Use emitter.setMaxListeners() to increase limit.
Trace
at EventEmitter.addListener (events.js:168:15)
at EventEmitter.once (events.js:189:8)
at route (C:\Users\Juan Pablo\pushserver.js:42:12)
at Server.onRequest (C:\Users\Juan Pablo\pushserver.js:32:3)
at Server.EventEmitter.emit (events.js:91:17)
at HTTPParser.parser.onIncoming (http.js:1793:12)
at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:111:23
)
at Socket.socket.ondata (http.js:1690:22)
at TCP.onread (net.js:402:27)
我有一行代码,只要发出通知事件,就会记录现有的侦听器。我已经运行了一段时间,它表明每个订阅客户端只有一个监听器(应该是),但是当我收到警告消息时,这行不在代码上。代码完全相同,除了那条线很难。
这是推送服务器的代码(因为我还在学习Node.js,所以它有点简陋):
var http = require('http');
var url = require("url");
var qs = require("querystring");
var events = require('events');
var util = require('util');
var emitter = new events.EventEmitter;
function onRequest(request, response)
{
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
request.setEncoding("utf8");
if (request.method == 'POST')
{
var postData = "";
request.addListener("data", function(postDataChunk)
{
postData += postDataChunk;
console.log("Received POST data chunk '"+ postDataChunk + "'.");
});
request.addListener("end", function()
{
route(pathname, response, postData);
});
}
else if (request.method=='GET')
{
var urlParts = url.parse(request.url, true);
route(pathname, response, urlParts.query);
}
}
function route(pathname, response, data)
{
switch (pathname)
{
case "/subscription":
emitter.once("event:notify", function(ids)
{
response.writeHead(200, {"Content-Type": "text/html", "Access-Control-Allow-Origin": "*"});
response.write(JSON.stringify(ids));
response.end();
});
break;
case "/notification":
//show how many listeners exist
console.log(util.inspect(emitter.listeners('event:notify'));
emitter.emit("event:notify", data.ids);
response.writeHead(200, {"Content-Type": "text/html", "Access-Control-Allow-Origin": "*"});
response.write(JSON.stringify(true));
response.end();
break;
default:
console.log("No request handler found for " + pathname);
response.writeHead(404, {"Content-Type": "text/plain", "Access-Control-Allow-Origin": "*"});
response.write("404 - Not found");
response.end();
break;
}
}
http.createServer(onRequest).listen(8888);
console.log('Server running at http://127.0.0.1:8888/');
我的印象是使用emitter.once会在使用后自动删除事件监听器,因此我不知道如果只连接了一个客户端,可以添加11个监听器。我想也许如果客户端在等待通知时断开连接,则不会处理关联的连接资源。
我想知道是否必须手动处理断开连接以及某处是否存在泄漏。欢迎任何建议。感谢。
答案 0 :(得分:2)
如果有人有兴趣,上面的代码确实泄露了。当客户端在发送通知之前断开连接时发生泄漏。要解决此问题,必须在客户端突然断开连接时删除事件侦听器,例如:
case "/subscription":
var notify = function(ids)
{
response.writeHead(200, {"Content-Type": "text/html", "Access-Control-Allow-Origin": "*"});
response.write(JSON.stringify(ids));
response.end();
}
emitter.once("event:notify", notify);
//event will be removed when connection is closed
request.on("close", function()
{
emitter.removeListener("event:notify", notify);
});
break;