在下载大型媒体文件时,请求会导致进程内存不足

我写了一个简单的脚本从CDN下载video文件,其中直接的URL很容易生成,例如http://something.com/N.mp4 ,其中N是一个数字。

问题是,当下载大于300MB的文件时,文件完全出现在硬盘上,但在request(...)的callback之前,内存分配失败:

 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 

如果您使用request模块进行callback,则会将整个响应主体caching在内存中。 尝试省略callback并使用fsstream的finish事件。

 var writer = fs.createWriteStream(__dirname + '/videos/' + fileName); writer.on('finish', function() { // ... index++; callback(null); }); request(url + fileName).pipe(writer); 

它看起来像是试图同时下载3到50个video,所以这可能是什么导致你用尽内存。 你可以尝试一系列的做法,看看是否解决了这个问题。 使用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.'); });