为什么" readFile"方法将文件的内容放入内存中,与#34; readFileSync"?相比较

时间:2015-02-26 14:29:28

标签: javascript node.js garbage-collection

以下是NodeJS代码(同步版本)的示例:

var fs = require('fs');
var path = './parseLogFiles/reports';
var counter = 0;
var totalFileSize = 0;
var fileName;
var fullPath;

function toMb (byteVal) {
    return (byteVal / 1048576).toFixed(2);
}

var filesList = fs.readdirSync(path);

console.log('Memory usage before files read:', toMb(process.memoryUsage()['heapUsed']) + ' MB');

for (var i = 0, len = filesList.length; i < len; i++) {

    fileName = filesList[i];

    if (fileName) {

        fullPath = path + '/' + fileName;

        totalFileSize += fs.statSync(fullPath)['size'];

        try {
            fs.readFileSync(fullPath, {encoding: 'utf8'});
        } catch(err){
            console.log('err: ', err);
        }

    }

}

console.log('Memory usage after files read:', toMb(process.memoryUsage()['heapUsed']) + ' MB');
console.log('Total files size:', toMb(totalFileSize) + ' MB');

我得到了以下结果:

文件读取前的内存使用情况:22.45 MB
读取文件后的内存使用情况:23.31 MB
文件总大小:258.19 MB

这是异步版本:

...

for (var i = 0, len = filesList.length; i < len; i++) {

    fileName = filesList[i];

    if (fileName) {

        fullPath = path + '/' + fileName;

        (function(fullPath){
            fs.stat(fullPath, function(err, stat){
                totalFileSize += stat['size'];
                fs.readFile(fullPath, {encoding: 'utf8'}, function(){
                    if (++counter === len) {
                        console.log('Memory usage after files read:', toMb(process.memoryUsage()['heapUsed']) + ' MB');
                        console.log('Total files size:', toMb(totalFileSize) + ' MB');
                    }
                });
            });
        })(fullPath);

    }

}

我得到了以下结果:

文件读取前的内存使用情况:22.45 MB
读取文件后的内存使用情况:437.88 MB
文件总大小:258.19 MB

为什么会发生(23.31 MB vs 437.88 MB)?

1 个答案:

答案 0 :(得分:2)

在同步版本中,数据会被垃圾收集,因为您没有将返回值分配给任何内容。在异步文件中,最终文件不允许被垃圾收集,因为它可以通过arguments访问,即使您没有设置显式参数。

为了证明这一点,我在一个文件上设置了一个简单的测试。我在基本版本中得到了与你类似的结果(尽管我必须在每次内存使用检查之前强制使用gc)。但是,如果我只存储readFileSync返回的数据,那么该版本使用的内存几乎与异步内存的数量完全相同。

如果您担心内存使用情况,则应使用fs.createReadStream