我写了一个简单的脚本来从CDN下载视频文件,其中直接URL很容易生成,例如 http://something.com/N.mp4 ,其中N是数字。
问题是,当下载大于300MB的文件时,文件完全显示在硬盘中,但在request(...)
的回调之前,内存分配失败:
FATAL ERROR: CALL_AND_RETRY_0 Allocation failed - process out of memory
这是否因为一些严重的不良做法而发生?可以request
下载此大小的媒体文件吗?
环境:Win7,4GB +空闲RAM,节点v0.10.31
var request = require('request');
var async = require('async');
var fs = require('fs');
var start = +process.argv[2] || 1;
var end = +process.argv[3] || 50;
var url = 'http://something.com/';
try {
fs.mkdirSync(__dirname + '/videos/');
} catch (e) {}
var index = start;
async.whilst(
function () { return index <= end; },
function (callback) {
var fileName = index + '.mp4';
console.log('Started: ' + fileName);
console.time('Done (' + fileName + ')');
request(url + fileName, function() {
console.timeEnd('Done (' + fileName + ')');
index++;
callback(null);
}).pipe(fs.createWriteStream(__dirname + '/videos/' + fileName));
},
function (err) {
if (err) {
return console.error(err);
}
console.log('Script finished.');
}
);
控制台输出示例:
> node index.js 3
Started: 3.mp4
Done (3.mp4): 296592ms
Started: 4.mp4
Done (4.mp4): 369718ms
Started: 5.mp4
FATAL ERROR: CALL_AND_RETRY_0 Allocation failed - process out of memory
答案 0 :(得分:5)
如果您使用带有回调的request
模块,它会将整个响应主体缓存在内存中。尝试省略回调并改为使用fs stream的finish
事件。
var writer = fs.createWriteStream(__dirname + '/videos/' + fileName);
writer.on('finish', function() {
// ...
index++;
callback(null);
});
request(url + fileName).pipe(writer);
答案 1 :(得分:-2)
您似乎正在尝试并行下载3到50个视频,因此这可能会导致您的内存不足。您可以尝试连续执行它们,看看是否能解决问题。使用async.waterfall
,您的代码可能如下所示:
var tasks = [];
for (; index < end; index++) {
tasks.push(function(callback) {
var fileName = index + '.mp4';
console.log('Started: ' + fileName);
console.time('Done (' + fileName + ')');
request(url + fileName, function() {
console.timeEnd('Done (' + fileName + ')');
callback(null);
}).pipe(fs.createWriteStream(__dirname + '/videos/' + fileName));
});
}
async.waterfall(tasks, function(err) {
if (err) {
return console.error(err);
}
console.log('Script finished.');
});