想封装一个网络连接,但跑着跑着就崩了
发布于 10 年前 作者 gvforjob 4046 次浏览 最后一次编辑是 8 年前 来自 问答

各位大神们,我想这样子封装一个网络连接,但在被拼命发包时进程内存涨到200M左右就崩掉了,是因为闭包的问题,还是Buffer拼接,还是因为一下子收到的数据包太多一次过用for处理,还是其他问题啊~~~ 我是一只小小小小鸟。。。。。。

var net = require('net');

function buildConnection(getPacks, buildPack) {
  return function(sock) {
    var self = this;
    this.buf = new Buffer(0);
    sock.on('data', function(data) {
	  self.buf = Buffer.concat([self.buf, data]);
	  var packs = getPacks(self);
	  for (var i = 0; i < packs.length; i++) {
	    // do something with pack
	  }
	}
  }
}
}

var Connection = buildConnection(aGetPacksfunction, aBuildPackfunction);

var server = net.createserver();
server.on('connection', function(sock) {
  var conn = new Connection(sock);
});
server.listen(8000);
6 回复

为啥没有错误信息呢?

@fish 控制台也没报错误消息,就是看着内存上到200M突然间就崩了

有2个原因吧:

  • v8对gc不是很积极,因为gc很昂贵。 v8对小内存对象更不积极,buffer对象是小内存,但是它hold住的数据在v8的heap外,所以会造成内存暴涨,因为buffer释放缓慢 . 你可以使用node xxx --export-gc 然后在程序里定时执行gc()。
  • 你在for循环时,低层libuv一直在接收数据 这个是属于proactor模式吧。底层一直在收,你可以通过接口sock.pause() and sock.resume()去控制接收buffer。

参考: https://github.com/clowwindy/shadowsocks-nodejs 的readme,作者目前放弃了nodejs版本就是因为内存的问题

self.buf = Buffer.concat([self.buf, data]);

我很好奇,这样不是每次都在self.buf后append data,self.buf不是会越来越大吗? 除非处理完pack后,重置了self.buf。 但这样tcp上的粘包没办法处理。

这是我的demo:

Session.prototype.append = function(buf) {
    if (!buf)
        return

    if (!this._buf) {
        this._buf = buf
        this._buf_len = buf.length
        return
    }

    var left = this._buf.length - this._buf_len
    if (left>=buf.length) {
        buf.copy(this._buf,this._buf_len)
        this._buf_len+=buf.length
        return
    }
    this._buf = Buffer.concat([this._buf.slice(0,this._buf_len),buf])
    this._buf_len+=buf.length
}

楼主,将代码用 markdown 语法标记一下

200M就跳票,好像还是比较奇怪的,还没到buffer上限

回到顶部