nodejs中的数组内存分配

问题描述 投票:0回答:2

我正在处理大量数组,

它包含〜200,000个元素。基本上是一个字符串数组。每个字符串的长度约为50个字符。环顾四周后,我发现1个字符需要2个字节,即1个元素需要100个字节。

因此,总的内存分配应加到200,000 * 100 = ~20 MB

[object-sizeofjs-sizeofsizeof似乎实现了相同的逻辑。

但是考虑一下此片段,

process.memoryUsage();
const paths = getAllFilePaths();
process.memoryUsage();

获取数组之前的输出,

external:25080
heapTotal:31178752
heapUsed:10427896 //10 MB
rss:51761152

获得数组后的输出,

external:16888
heapTotal:173539328
heapUsed:134720896 //134 MB
rss:204070912

这是heapUsed的〜124MB附加内容。

getAllFilePaths()的实现:

const getAllFilePaths = function (_path, paths = []) {

    fs.readdirSync(_path).forEach(name => {
        const stat = fs.lstatSync(joinPath(_path, name))
        if (stat.isDirectory()) {
            getAllFilePaths(joinPath(_path, name), paths);
            return;
        }

        paths.push(joinPath(_path, name));
    });

    return paths;
};

为什么要使用那么多的内存?这是所需的行为,还是getAllFilePaths()函数可能正在泄漏内存?

javascript arrays node.js v8
2个回答
1
投票

在这里做了小测试:Memory Leak Test

这似乎表明将200,000个50个字符的项目硬编码为一个数组,将输出以下内容:

{ 
rss: 58232832,
heapTotal: 40378368,
heapUsed: 25490136, // ~25 MB
external: 8272 
}

0
投票

V8开发人员在这里。我想到两点来解释您的期望和度量之间的差异:

(1)字符串数组比字符串的字符需要更多的内存。在内存中,字符串对象的标头在64位系统上占用16个字节(指针大小[1]“形状”指针加上两个用于散列和长度的32位字段)。根据字符串构造的精确程度,它们在内部可能还会使用不同的表示形式。标头+字符是最简单的形式。此外,数组本身每个元素都有一个指针大小的条目,至少增加了200,000 * 8字节= 1.5MB-动态增长的数组在必须增长时会过度分配,因此不必增长每次添加,如果数组不够幸运,可能在分配过多后浪费空间。

(2)AFAIK process.memoryUsage()仅返回当前堆使用情况统计信息,其中可能包含先前操作留下的垃圾。为了确定某物的内存消耗,建议在每次测量之前显式触发一个完整的GC周期。具体来说:以--expose-gc开头Node,并在每个global.gc()之前调用process.memoryUsage()

为了完整起见,我将提到:字符串根据其内容可以占用每个字符1或2个字节。对于每个单独的字符串,每个字符占用相同的数量,因此单个非ASCII字符会强制整个字符串为两个字节。对于嵌入程序提供的字符串(如文件名),嵌入程序还必须配合使用以支持一字节优化。我不知道Node的文件API是否可以做到这一点。

[1]“指针大小”表示当今64位= 8字节;随着“ pointer-compression”在V8 8.0中变得可用,它缩小到4个字节(如果您选择部署指针压缩的版本)。

© www.soinside.com 2019 - 2024. All rights reserved.