Node.js切断一个耗尽内存的非常大的缓冲区

时间:2016-10-07 13:16:58

标签: javascript node.js performance

我有一个非常大的base64编码字符串,需要读入一个字节(Uint8)数组,然后将该字节数组拆分为指定大小的块,它们分别对这些块进行编码。使用下面的函数可以工作但是调用.slice或.toString会增加每次调用时堆上的内存,因为(我相信)它正在复制缓冲区。在特别大的base64Encoded字符串上,应用程序将在堆上空间不足。可以做些什么来将其拆分为指定的大小,base64对它们进行编码而不会耗尽内存?

const process = function (reallyLargeBase64EncodedString, splitSize){

var theBuffer = Buffer.from(reallyLargeBase64EncodedString, 'base64');

//var tempBuffer = new Buffer(splitSize);
for (var start = 0; start < theBuffer.length; start += splitSize) {
    //for(var z = 0; z < splitSize; z++){
        //tempBuffer.writeUInt8( theBuffer[start+z],z);
    //}
    //var base64EncodedVal = tempBuffer.toString('base64');
    //var base64EncodedVal = theBuffer.buffer.toString('base64', start, start+splitSize);
    var base64EncodedVal = theBuffer.slice(start,start+splitSize).toString('base64'); 
    //do stuff with the base64 encoded value
}

};

1 个答案:

答案 0 :(得分:5)

我建议使用node的流媒体接口来处理那些大的东西。如果您的base64编码字符串来自文件或网络请求,您可以直接从输入管道传输到base64解码流,如base64-stream

为了对数据进行分块并重新编码每个块,您必须编写自己的变换流(输入和输出之间的流)。这看起来像

// NOTE: the following code has been tested in node 6.
// since it relies on the new Buffer api, it must be run in 5.10+
var Transform = require('stream').Transform;

class ChunkEncode extends Transform {
    constructor(options){
        super(options);
        this.splitSize = options.splitSize;
        this.buffer = Buffer.alloc(0);
    }

    _transform(chunk, encoding, cb){
        // chunk is a Buffer;
        this.buffer = Buffer.concat([this.buffer, chunk]);
        while (this.buffer.length > this.splitSize){
            let chunk = this.buffer.slice(0, this.splitSize);
            // Encode and write back to the stream.
            this.push(chunk.toString('base64')) 
            // throw in a newline for visibility.
            this.push('\n');
            // chop off `splitSize` from the start of our buffer.
            this.buffer = this.buffer.slice(this.splitSize);
        }
    }
}

然后你应该可以做类似

的事情
 var fs     = require('fs');
 var base64 = require('base64-stream');

 fs.createReadStream('./long-base64-string')
 .pipe(base64.decode())
 .pipe(new ChunkEncode({splitSize : 128}))
 .pipe(process.stdout) 

这将记录到标准输出,但您可以轻松地写入文件或网络流。如果您需要进一步操作数据,您可以创建一个写入流,这样您就可以对每个数据块执行某些操作。