RSS est une mesure raisonnable de "l'utilisation totale de la mémoire du processus d'interprétation de Node.js". Vous devez simplement être en mesure d'exécuter votre programme si cela dépasse la RAM disponible. Notez toutefois qu'il exclut certains types de mémoire, de sorte que la consommation réelle de mémoire sur un serveur qui n'exécute qu'un seul processus pourrait être plus élevée (VSZ est le pire cas).
Le concept de RSS est défini dans le noyau Linux lui-même, comme indiqué à l'adresse suivante : Qu'est-ce que RSS et VSZ dans la gestion de la mémoire sous Linux ? et mesure l'utilisation totale de la mémoire du processus. Cette valeur peut donc être mesurée par des programmes externes tels que ps
sans connaissance de l'interne de Node.js, par exemple comme indiqué à : Récupérer l'utilisation du CPU et de la mémoire d'un seul processus sous Linux ?
heapTotal
y heapUsed
sont des concepts internes à l'implémentation de Node.js. Il serait bon de regarder le code source de la v8 pour les comprendre plus précisément, notamment je me demande s'ils obtiennent simplement ces valeurs de la glibc avec des fonctions telles que celles mentionnées à : Appel API pour obtenir la taille actuelle du tas d'un processus ? ou s'il a sa propre gestion de tas de données par dessus.
Pour le concept de tas en général, voir également : Que sont la pile et le tas et où sont-ils ? y Quelle est la fonction des instructions push / pop utilisées sur les registres en assembleur x86 ? Le tas a de grandes chances de prendre la majorité de la mémoire dans un programme JavaScript, je ne pense pas que vous vous donnerez la peine d'essayer de chercher cette mémoire ailleurs (à part peut-être les tableaux typés, qui sont présentés séparément dans la section process.memoryUsage()
).
L'exemple de code suivant peut être utilisé pour effectuer des tests simples que j'ai essayé d'analyser : https://cirosantilli.com/javascript-memory-usage-benchmark Mais à la différence des langages sans garbage collection comme le C++, il est très difficile de prédire pourquoi l'utilisation de la mémoire est parfois si exagérée, surtout lorsque nous avons un petit nombre d'objets. Je ne suis pas sûr que les autres langages avec garbage collection fassent mieux.
Vous devez exécuter le programme avec :
node --expose-gc main.js
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())
}
Quelques choses que nous avons appris sur Node 16 Ubuntu 21.10 :
- avec
node --expose-gc bench_mem.js n 1
nous voyons que le RSS minimum est de 30 MiB et le minimum heapUsed
3.7 MB. A titre de comparaison, le RSS pour un hello world en C sur le même système est de 770 kB