我在Node.js上有服务器端的基于TCP的客户端/服务器应用程序。因为TCP是一个流,我需要单独的数据包,所以我会在每个数据包之前发送两个字节的长度(我猜通常的做法)。大数据包可以有几个块(因为MTU和其他东西)所以我需要从当前缓冲区中提取我可以的每个数据包,并留下其余的用于加入下一个传入的块并再次解析。我提出了以下代码:
function parsePackets(data) {
// join existing buffer contents with new chunk
var buffer = Buffer.concat([this.buffer, data]);
var start = 0;
var end = buffer.length;
var packets = [];
while (true) {
// wait for at least two bytes
if (end - start < 2) {
break;
}
var length = buffer.readUInt16BE(start);
// wait until we can read whole packet
if (end - start < length) {
break;
}
// push packet data as a separate packet
//var data = new Buffer(length);
//buffer.copy(data, 0, start, start + length);
var data = buffer.slice(start, start + length);
packets.push(data);
start += length;
}
// drop parsed buffer contents, leaving the rest
//var newBuffer = new Buffer(buffer.length - start);
//buffer.copy(newBuffer, 0, start, buffer.length);
//this.buffer = newBuffer;
this.buffer = buffer.slice(start, buffer.length);
return packets;
}
我担心的是:切掉缓冲区内容会被垃圾收集吗?我还做concat
返回新的缓冲区(我假设从提供的缓冲区复制内容,这意味着它们可以被垃圾收集)。或者我可能需要使用copy
而不是slice
(我在注释行中有一个示例)?
我想要没有内存泄漏的高性能代码,所以我不想复制更多的数据。但目前看来我的应用程序的内存使用量越来越大(我不知道如何测试它以及如何检查切片内容是否会在某个时候被释放)。
答案 0 :(得分:1)
在Buffer中,实际上没有任何切片。使用切片操作,会创建一个新的缓冲区视图,该视图指向新位置并具有自己的长度。修改原始缓冲区也会修改切片缓冲区。 根据您的代码,您只能在Buffer.concat中创建一个新缓冲区。之后,您将其几个块分配给数据包并放入this.buffer。所有这些缓冲区都将指向通过concat方法创建的原始缓冲区。这是最可行的内存效率方法,它不会产生任何问题,直到2个块没有重叠内存。
答案 1 :(得分:1)
代码中没有累积的缓冲区对象泄漏。
您不再在代码中保留引用的任何Buffer对象将立即可用于垃圾回收。因此,每次调用parsePackets()
时,都会使用.concat()
和.slice()
创建几个新的缓冲区对象,但每次只在this.buffer
中保留对一个缓冲区对象的引用实例变量以及每次用新缓冲区替换缓冲区(使前一个缓冲区符合垃圾收集条件)。
因此,此代码中没有缓冲对象的累积或累积泄漏。
为了获得完整的代码清洁度,您需要确保在读完所有数据后,this.buffer
中存储的最后一个缓冲区对象会被this.buffer = null;
清除,因此无法参考即使处理完成,也会保留。对于持有此引用的对象本身是清理的,这不是必需的。