MemyUse()的返回值表示什么?

根据官方文件(来源) :

Memory 用法()

返回一个对象,该对象描述 Node 进程的内存使用情况 以字节为单位的。

var util = require('util');


console.log(util.inspect(process.memoryUsage()));

这将产生:

{ rss: 4935680, heapTotal: 1826816, heapUsed: 650472 }

HeapTotal 和 heapUsed 指的是 V8的内存使用情况。

RssHeapTotal被利用了到底代表什么?

这可能看起来是一个微不足道的问题,但我一直在寻找,我无法找到一个明确的答案,迄今为止。

51057 次浏览

RSS 常驻集合大小常驻集合大小,进程内存在 RAM 中的部分(与交换空间或文件系统中的部分相反)。

一大堆是新分配的对象将来自的内存部分(想想 C 中的 malloc或 JavaScript 中的 new)。

您可以在 维基百科上阅读关于堆的更多信息。

为了回答这个问题,我们必须首先理解 V8的内存方案。

正在运行的程序总是通过内存中分配的一些空间来表示。这个空间叫做 居民集。V8使用类似于 Java 虚拟机的方案,将内存划分为若干段:

  • Code : 正在执行的实际代码
  • Stack : 包含所有值类型(如整数或布尔值) ,指针引用堆上的对象,指针定义程序的控制流
  • : 一个内存段,专门用于存储对象、字符串和闭包等引用类型。 enter image description here

现在很容易回答这个问题:

  • Rss : 驻留集大小
  • HeapTotal : 堆的总大小
  • heapUsed : 堆实际上已经使用过了

参考文献 : < a href = “ http://apmblog.dynatrace.com/2015/11/04/understand-愈垃圾收集和狩猎-内存泄漏-in-node-js/”rel = “ norefrer”> http://apmblog.dynatrace.com/2015/11/04/understanding-garbage-collection-and-hunting-memory-leaks-in-node-js/

Node.js 文档的描述如下:

HeapTotal 和 heapUsed 表示 V8的内存使用情况 管理绑定到 JavaScript 对象的 C + + 对象的内存使用 Rss,即 常驻集合大小,是 主存储器设备(即总分配内存的子集) 进程,包括堆、代码段和堆栈。

所有提到的值都以字节表示。所以,如果你只是想打印它们,你可能需要将它们重新缩放到 MB:

const used = process.memoryUsage();
for (let key in used) {
console.log(`Memory: ${key} ${Math.round(used[key] / 1024 / 1024 * 100) / 100} MB`);
}

这样就会得到如下输出:

Memory: rss 522.06 MB
Memory: heapTotal 447.3 MB
Memory: heapUsed 291.71 MB
Memory: external 0.13 MB

让我们用一个示例来做这件事

下面的示例将向您展示内存使用的增加如何实际增加 rssheapTotal

const numeral = require('numeral');
let m = new Map();
for (let i = 0; i < 100000; i++) {
m.set(i, i);
if (i % 10000 === 0) {
const { rss, heapTotal } = process.memoryUsage();
console.log( 'rss', numeral(rss).format('0.0 ib'), heapTotal, numeral(heapTotal).format('0.0 ib') )
}
}

跑步上面的步骤会给你带来这样的效果:

rss 22.3 MiB 4734976 4.5 MiB
rss 24.2 MiB 6483968 6.2 MiB
rss 27.6 MiB 9580544 9.1 MiB
rss 27.6 MiB 9580544 9.1 MiB
rss 29.3 MiB 11419648 10.9 MiB
rss 29.3 MiB 11419648 10.9 MiB
rss 29.3 MiB 11419648 10.9 MiB
rss 32.8 MiB 15093760 14.4 MiB
rss 32.9 MiB 15093760 14.4 MiB
rss 32.9 MiB 15093760 14.4 MiB

这清楚地向您展示了如何使用变量并不断增加它所需的空间来增加 heapTotal 和相应的驻留集大小(rss)

RSS 是“ Node.js 解释器进程的总内存使用量”的合理度量。如果超过了可用的 RAM,您只需要运行程序即可。但是请注意,它排除了某些类型的内存,因此仅运行单个进程的服务器上的实际内存消耗可能更高(VSZ 是最糟糕的情况)。

RSS 的概念是在 Linux 内核中定义的,如下所示: 什么是 Linux 内存管理中的 RSS 和 VSZ中提到的,它测量进程的总内存使用量。因此,这个值可以通过外部程序(如 ps)来衡量,而不需要了解 Node.js 的内部结构,例如: 在 Linux 上检索单个进程的 CPU 使用量和内存使用量?所示

heapTotalheapUsed是 Node.js 实现的内部概念。最好查看一下 v8的源代码,以便更精确地理解它们,值得注意的是,我想知道它们是否只是从 glibc 获取这些值,并使用如下所提到的函数: API 调用来获取当前堆大小的进程?中的函数,即它是否在其上进行了自己的堆管理。

关于堆的概念,请参阅: 堆栈和堆在什么地方?在 x86汇编的寄存器上使用的推/弹指令的功能是什么?堆很可能占据 JavaScript 程序的大部分内存,我不认为你会费心去其他地方寻找那些内存(也许除了类型化的数组,它们在 process.memoryUsage()下单独显示)。

下面的代码示例可以用来做一些简单的测试,我已经尝试分析过了: https://cirosantilli.com/javascript-memory-usage-benchmark但是不像没有 C + + 这样的垃圾收集的语言,很难预测为什么内存使用有时会如此夸大,特别是当我们有较少数量的对象时。不过,我不确定其他垃圾收集语言是否做得更好。

你必须用以下方法运行程序:

node --expose-gc main.js

主要的

#!/usr/bin/env node


// CLI arguments.
let arr = false
let array_buffer = false
let dealloc = false
let klass = false
let obj = false
let n = 1000000
let objn = 0
for (let i = 2; i < process.argv.length; i++) {
switch (process.argv[i]) {
case 'arr':
arr = true
break
case 'array-buffer':
array_buffer = true
break
case 'class':
klass = true
break
case 'dealloc':
dealloc = true
break
case 'obj':
obj = true
break
case 'n':
i++
n = parseInt(process.argv[i], 10)
break
case 'objn':
i++
objn = parseInt(process.argv[i], 10)
break
default:
console.error(`unknown option: ${process.argv[i]}`);
break
}
}


class MyClass {
constructor(a, b) {
this.a = a
this.b = b
}
}


let a
if (array_buffer) {
a = new Int32Array(new ArrayBuffer(n * 4))
for (let i = 0; i < n; i++) {
a[i] = i
}
} else if (obj) {
a = []
for (let i = 0; i < n; i++) {
a.push({ a: i, b: -i })
}
} else if (objn) {
a = []
for (let i = 0; i < n; i++) {
const obj = {}
for (let j = 0; j < objn; j++) {
obj[String.fromCharCode(65 + j)] = i
}
a.push(obj)
}
} else if (klass) {
a = []
for (let i = 0; i < n; i++) {
a.push({ a: i, b: -i })
}
} else if (klass) {
a = []
for (let i = 0; i < n; i++) {
a.push(new MyClass(i, -i))
}
} else if (arr) {
a = []
for (let i = 0; i < n; i++) {
a.push([i, -i])
}
} else {
a = []
for (let i = 0; i < n; i++) {
a.push(i)
}
}


if (dealloc) {
a = undefined
}


let j
while (true) {
if (!dealloc) {
j = 0
// The collector somehow removes a if we don't reference it here.
for (let i = 0; i < n; i++) {
if (obj || klass) {
j += a[i].a + a[i].b
} else if (objn) {
const obj = a[i]
for (let k = 0; k < objn; k++) {
j += obj[String.fromCharCode(65 + k)]
}
} else if (arr) {
j += a[i][0] + a[i][1]
} else {
j += a[i]
}
}
console.error(j)
}
global.gc()
console.error(process.memoryUsage())
}

我们在 Node 16 Ubuntu 21.10上学到了一些东西:

  • 使用 node --expose-gc bench_mem.js n 1,我们可以看到 RSS 的最小值为30MiB,而 heapUsed的最小值为3.7 MB。相同系统上的 C hello world 的 RSS 为770kB,以供比较