为什么“;readFile”;使用比读取文件更多的内存's的内容长度

Why does "readFile" use more memory than the read file's content length?

本文关键字:内存 readFile 文件 读取 为什么      更新时间:2024-05-19

我有一个包含大约300000个日志文件的路径。当我使用"readFile"方法读取所有这些文件时,我注意到内存消耗(泄漏)。

以下是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;
        (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);
    }
}

我得到了以下结果:

Memory usage before files read: 22.45 MB
Memory usage after files read: 437.80 MB
Total files size: 258.19 MB

(437.80-22.45)/258.19=1.6(使用的内存超过读取文件的内容长度)

但如果我使用"readFileSync"方法,我不会注意到内存消耗(泄漏)。

以下是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');

我得到了以下结果:

Memory usage before files read: 22.45 MB
Memory usage after files read: 23.31 MB
Total files size: 258.19 MB

没有内存消耗(泄漏)。

为什么会发生这种情况?

为什么"readFile"使用的内存比读取文件的内容长度多?

根据ECMAscript规范,Javascript字符串在UTF-16或UCS-2中内部表示,这两种字符串都需要至少到个字节来表示文件中的每个"字符"。当您将主要由ASCII字符组成的文本文件作为Javascript字符串加载到内存中时,其大小可能会增加一倍。

这与是否有内存泄漏的证据的问题是正交的。

(我想说的是,你没有泄漏的证据。为了证明泄漏的存在,你需要显示堆大小在多个垃圾收集周期内呈上升趋势的静态信息。你只是在加载文件之前和之后报告一个显示堆使用情况差异的信息。)