在使用 Node.js 合并文件分片时出现了标题的错误信息。
代码分析
m.merge = (opts) => {
return new Promise((resolve, reject) => {
const { filename, target } = opts;
try {
let len = 0;
const bufferList = fs.readdirSync(`${STATIC_TEMPORARY}/${filename}`).map((hash, index) => {
const buffer = fs.readFileSync(`${STATIC_TEMPORARY}/${filename}/${index}`);
len += buffer.length;
return buffer;
});
// Merge files
const buffer = Buffer.concat(bufferList, len);
const ws = fs.createWriteStream(`${target}/${filename}`);
ws.write(buffer);
ws.close();
resolve({ success: true, msg: 'Section merge completed' });
} catch (error) {
console.error(error);
reject({ success: false, msg: error });
}
});
};
const buffer = Buffer.concat(bufferList, len);
定位到是上边这行出现了问题,检查了一下服务器,node应用的内存占用是 192.1mb。
这时原因就很明了,是因为文件分片太大导致内存耗尽,没有可用空间了。
优化方法
上面的做法是把所有的文件分片都concat然后写到流中,正是在这个过程中导致了内存耗尽。
其实,我们可以按顺序分多次concat写入,修改代码如下:
m.merge = (opts) => {
return new Promise((resolve, reject) => {
const { filename, target } = opts;
try {
// 优化
const ws = fs.createWriteStream(`${target}/${filename}`);
const bufferList = fs.readdirSync(`${STATIC_TEMPORARY}/${filename}`)
let len = 0;
let list = []
bufferList.forEach((hash, index) => {
const b = fs.readFileSync(`${STATIC_TEMPORARY}/${filename}/${index}`);
len += b.length;
list.push(b)
if (len > 10485760) { // 10M
const buffer = Buffer.concat(list, len);
ws.write(buffer);
len = 0;
list = []
}
})
ws.close();
resolve({ success: true, msg: 'Section merge completed' });
} catch (error) {
console.error(error);
reject({ success: false, msg: error });
}
});
};
这是重新调用接口就不会出现标题的错误了,文件可以合并成功。但是查看一下Node进程的内存占用 却仍然保持在192.1mb左右。
这就需要对Node做一下具体的内存分析了。