177 votes

A quoi correspondent les valeurs de retour de node.js process.memoryUsage() ?

D'après la documentation officielle ( source ) :

process.memoryUsage()

Renvoie un objet décrivant l'utilisation de la mémoire du processus Node. mesurée en octets.

var util = require('util');

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

Cela va générer :

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

heapTotal et heapUsed font référence à l'utilisation de la mémoire de V8.

Exactement ce que rss , heapTotal y heapUsed représentent-ils ?

Cette question peut sembler banale, mais j'ai cherché et je n'ai pas trouvé de réponse claire jusqu'à présent.

271voto

Tim Qian Points 1461

Pour répondre à cette question, il faut d'abord comprendre le schéma de mémoire de V8.

Un programme en cours d'exécution est toujours représenté par un espace alloué en mémoire. Cet espace est appelé Ensemble résident . V8 utilise un schéma similaire à celui de la machine virtuelle Java et divise la mémoire en segments :

  • Code : le code réel exécuté
  • Pile : contient tous les types de valeurs (primitives comme les entiers ou les booléens) avec des pointeurs référençant des objets sur le tas et des pointeurs définissant le flux de contrôle du programme.
  • Amas : un segment de mémoire dédié au stockage des types de référence comme les objets, les chaînes de caractères et les fermetures. enter image description here

Il est maintenant facile de répondre à la question :

  • rss : Taille de l'ensemble des résidents
  • heapTotal : Taille totale du tas
  • heapUsed : Heap effectivement utilisé

Réf. : http://apmblog.dynatrace.com/2015/11/04/understanding-garbage-collection-and-hunting-memory-leaks-in-node-js/

42voto

Ray Toal Points 35382

RSS es el taille de l'ensemble des résidents Il s'agit de la partie de la mémoire du processus conservée dans la RAM (par opposition à l'espace d'échange ou à la partie conservée dans le système de fichiers).

Le site amas est la portion de mémoire d'où proviendront les objets nouvellement alloués (pensez à malloc en C, ou new en JavaScript).

Vous pouvez en savoir plus sur le tas à l'adresse suivante Wikipedia .

22voto

bvdb Points 898

Le site Documentation sur Node.js le décrit comme suit :

heapTotal et heapUsed se référer à l'utilisation de la mémoire de V8. externe se réfère à l'utilisation de la mémoire des objets C++ liés à des objets JavaScript gérés par V8. rss, Taille de l'ensemble des résidents est la quantité d'espace occupée dans le mémoire principale (c'est-à-dire un sous-ensemble de la mémoire totale allouée) pour le processus, qui comprend le tas, le segment de code et la pile.

Toutes les valeurs mentionnées sont exprimées en octets. Donc, si vous voulez simplement les imprimer, vous voudrez probablement les remettre à l'échelle MB :

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

Cela vous donnera une sortie comme :

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

3voto

Cherag Verma Points 219

Faisons-le avec un exemple

L'exemple suivant vous montre comment l'augmentation de l'utilisation de la mémoire va en fait augmenter le temps de réponse de l'ordinateur. rss y heapTotal

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') )
    } 
}

En exécutant la commande ci-dessus, vous obtiendrez quelque chose comme ceci :

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

Cela montre clairement comment l'utilisation d'une variable et l'incrémentation continue de l'espace dont elle a besoin augmentent le HeapTotal et, par conséquent, la Resident Set Size( rss )

3voto

Ciro Santilli Points 3341

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X