Node.js + Twitter 流内存泄漏

Node.js + Twitter Streaming memory leak

以下是 运行 作为 PM2 在 Ubuntu 机器上的服务。内存占用从 40MB 稳步上升到 95MB,此时服务器停止发出但不会使 PM2 进程崩溃。这导致网页没有响应。

此代码在收到推文时仅发送套接字发射。当没有人连接时它不会发出事件,但内存使用量仍然增加,所以它可能与 SocketIO 无关。

只是想知道 client.stream 中的什么可能导致此泄漏。我安装了 memwatch 但没有出现。

var express = require('express');
var Twitter = require('twitter');
var login = require('./credentials');

var connections = 0;
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.use(express.static('public'));

String.prototype.startsWith = function(str){
    return this.indexOf(str) === 0;
};

var client = new Twitter({
    consumer_key: login.creds['consumer_key'],
    consumer_secret: login.creds['consumer_secret'],
    access_token_key: login.creds['access_token_key'],
    access_token_secret: login.creds['access_token_secret']
})

client.stream('statuses/filter', {track: 'drake'}, function(stream) {
    stream.on('data', function(tweet) {
        var imageUrl = undefined;
        try {
            imageUrl = tweet.entities.media[0].media_url;
        }
        catch(err) {
            // Ignored
        }
        abridgedTweet = {'text': tweet.text, 'author': tweet.user.screen_name, 'picture': imageUrl};
        if (connections > 0 && !(tweet.text.startsWith("RT")) && !(tweet.text.startsWith("@")) && tweet.lang == "en") {
            io.emit('tweet', abridgedTweet);
        };
    });
    stream.on('error', function(error) {
        console.log("ERROR: " + error);
    })
});

app.get('/', function(req, res){
    res.sendFile(__dirname + '/index.html');
});

io.on('connection', function(socket){
    console.log('A user connected');
    connections += 1;
    socket.on('disconnect', function() {
        console.log("A user disconnected");
        connections -= 1;
        console.log(connections + " users remaining");
    });
});

http.listen(3000, function(){
  console.log('listening on *:3000, pid: ' + process.pid);
});

编辑:我删除了 stream.on('data') 块中的所有内容,但内存使用量仍在增加。

这是人们在开始使用 PM2 并且能够清楚地看到内存使用情况时询问的常见问题。 Node.js 使用 Google 的 V8 JavaScript 引擎,它实现了垃圾收集器。 V8 使用的 GC 算法将尝试占用尽可能多的内存,并且在清理未使用的内存时非常懒惰。因此,通常 Node 进程会继续增加内存使用量,直到 GC 认为最好释放内存的某个点。请注意,Node 进程的硬内存限制为 1.4 GB。

有一种方法可以强制 GC 释放内存,使用 --expose-gc 标志。 运行 你的服务器是这样的:

node --expose-gc yourscript.js

并在您的应用程序中的某处附加以下循环。这将强制每 30 秒进行一次垃圾收集。

setInterval(function(){
  global.gc();
  console.log('GC done')
}, 1000*30);

如果您使用的是 PM2,则需要做额外的工作来传递 --expose-gc 标志。请注意,在实践中,您可能应该避免进行手动垃圾收集,而让 V8 进行它的工作。

其次,尽管显然没有做任何事情,但您的进程首先增加的原因可能是 PM2 本身。 PM2 在集群模式下默认 运行s,与 fork 模式相反。集群模式将 运行 一些后台进程,因此随着时间的推移会增加内存。该内存最终会在某个时刻被 GC 释放。如果您 运行 PM2 而不是 fork 模式,当进程空闲时,您的内存占用应该保持在同一水平。