Heim > Artikel > Web-Frontend > Lassen Sie uns über den GC-Mechanismus (Garbage Collection) in Node.js sprechen
Wie führt
Node GC (Garbage Collection) durch? Der folgende Artikel führt Sie durch.
GC, Garbage Collection, Garbage Collection. In der Programmierung bezieht sich der Begriff im Allgemeinen auf den automatischen Speicherrecyclingmechanismus, der regelmäßig nicht benötigte Daten löscht.
Node.js verwendet die darunter liegende V8-Engine. V8 ist eine leistungsstarke JavaScript-Engine, die von Google als Open-Source-Lösung bereitgestellt und in C++ geschrieben wurde. [Verwandte Tutorial-Empfehlungen: nodejs-Video-Tutorial]
Node.js-Speicher ist hauptsächlich in drei Teile unterteilt:
Coderaum: wo Codesegmente gespeichert werden;
Stack: temporäre Variablen, die durch den Funktionsaufruf generiert werden Stapel, Für einige Grundtypen wie Zahlen, Zeichenfolgen, boolesche Werte und Objektreferenzen (die Adresse wird gespeichert, nicht das Objekt selbst).
Heap: speichert Daten wie Objekte;
Node.js verwendet unten den Speicherrecyclingmechanismus von V8.
Zunächst werden alle Objekte in JS im Heap-Speicher gespeichert. Wenn der Prozess erstellt wird, wird eine anfängliche Größe des Heap-Speichers zugewiesen und dann werden unsere Objekte darin platziert.
Wenn immer mehr Objekte vorhanden sind, reicht der Heap-Speicher nicht aus und der Heap-Speicher wird dynamisch erweitert. Wenn eine maximale Grenze erreicht wird (heutzutage normalerweise 4 GB), tritt ein Heap-Überlauffehler auf und der Node.js-Prozess wird beendet.
V8 unterteilt den Speicher zunächst in zwei Teile oder zwei Generationen:
Junge Generation: speichert einige Objekte mit kurzer Überlebenszeit;
Alte Generation: speichert Objekte, die dies getan haben eine lange Überlebenszeit oder sind dauerhaft.
Die neue Generation ist sehr klein und einige Objekte mit kurzer Überlebenszeit werden hier gespeichert. Normalerweise werden sie häufig recycelt (z. B. einige temporäre Objekte im Aufrufstapel von Funktionen).
Die Größe der neuen Generation kann über
node --max-semi-space-size=SIZE index.js
in MB geändert werden.node --max-semi-space-size=SIZE index.js
修改新生代的大小,单位为 MB。另外,老生代则通过
Darüber hinaus verwendet die alte Generation--max-old-space-size=SIZE
--max-old-space-size=SIZE
, um den Scavenge-Algorithmus der neuen Generation festzulegen
Die neue Generation wird in zwei Räume aufgeteilt. Sie sind:
Wenn der From-Bereich fast voll ist, werden wir ihn durchqueren, um die aktiven Objekte zu finden und sie in den To-Bereich kopieren. Zu diesem Zeitpunkt ist der From-Bereich tatsächlich leer, und dann tauschen wir die Identitäten von From und To aus.
Wenn einige Objekte mehrmals kopiert werden, wird davon ausgegangen, dass sie eine längere Überlebenszeit haben, und sie werden in die alte Generation verschoben. Der Vorteil dieses kopierbasierten Algorithmus besteht darin, dass er das Problem der Speicherfragmentierung sehr gut bewältigen kann. Der Nachteil besteht darin, dass er beim Verschieben von Speicherplatz etwas Platz verschwendet Nicht geeignet, um zu viel Speicherplatz zuzuweisen. Es handelt sich eher um einen Hilfs-GC.Mark-Sweep und Mark-Compact
Der Raum der alten Generation ist viel größer als der der neuen Generation. Er enthält einige langlebige Objekte und verwendet den Mark-Sweep-Algorithmus (Mark Clearing).
Dieser Ansatz führt zu einer Fragmentierung des freien Speicherplatzes. Wenn wir ein großes zusammenhängendes Objekt erstellen, können wir keinen Platz finden, an dem wir es ablegen können. Zu diesem Zeitpunkt muss Mark-Compact (Markierungskomprimierung) verwendet werden, um die fragmentierten aktiven Objekte zu integrieren.
Mark-Compact verschiebt alle aktiven Objektkopien an ein Ende, und auf der anderen Seite der Grenze befindet sich dann ein ganzer Block zusammenhängenden verfügbaren Speichers.
Angesichts der Tatsache, dass Mark-Sweep und Mark-Compact lange dauern und den JavaScript-Thread blockieren, führen wir normalerweise nicht alles auf einmal aus, sondern verwenden die inkrementelle Markierung (Inkrementelle Markierung). Das bedeutet, zeitweise zu markieren, kleine Schritte zu unternehmen und Garbage Collection und Anwendungslogik abzuwechseln.
Darüber hinaus führt V8 auch eine parallele Markierung und parallele Reinigung durch, um die Ausführungseffizienz zu verbessern.
Über die Methode „process.memoryUsage“ können wir einige speicherbezogene Informationen abrufen. Der Ausgabeinhalt ist: Erläuterung rss: Größe des residenten Satzes (residente Satzgröße), einschließlich Codefragmenten, Heap-Speicher, Stapel usw. heapTotal: die gesamte Heap-Speichergröße von V8; heapUsed: der belegte Heap-Speicher; external: die Speichergröße außer V8, die sich auf den von C++-Objekten belegten Speicher bezieht, z Pufferdaten. arrayBuffers: Die Speichergröße im Zusammenhang mit 以上数字的单位都是字节。 写一个脚本,用一个定时器,让一个数组不停地变大,并打印堆内存使用情况,直到内存溢出。 需要特别注意的是,不要用 Buffer 做测试。 因为 Buffer 是 Node.js 特有的处理二进制的对象,它不是在 V8 中的实现的,是 Node.js 用 C++ 另外实现的,不通过 V8 分配内存,属于堆外内存。 我使用电脑是 macbook pro M1 Pro,Node.js 版本为 Die Einheiten der oben genannten Zahlen sind Bytes. Testen Sie das maximale SpeicherlimitSpeicherbezogene Informationen anzeigen
process.memoryUsage();
{
rss: 35454976,
heapTotal: 7127040,
heapUsed: 5287088,
external: 958852,
arrayBuffers: 11314
}
ArrayBuffer
und SharedArrayBuffer
, die Teil von external ist. ArrayBuffer
和 SharedArrayBuffer
相关的内存大小,属于 external 的一部分。测试最大内存限制
const format = function (bytes) {
return (bytes / 1024 / 1024).toFixed(2) + " MB";
};
const printMemoryUsage = function () {
const memoryUsage = process.memoryUsage();
console.log(
`heapTotal: ${format(memoryUsage.heapTotal)}, heapUsed: ${format(
memoryUsage.heapUsed
)}`
);
};
const bigArray = [];
setInterval(function () {
bigArray.push(new Array(20 * 1024 * 1024));
printMemoryUsage();
}, 500);
v16.17.0
heapTotal: 164.81 MB, heapUsed: 163.93 MB
heapTotal: 325.83 MB, heapUsed: 323.79 MB
heapTotal: 488.59 MB, heapUsed: 483.84 MB
...
heapTotal: 4036.44 MB, heapUsed: 4003.37 MB
heapTotal: 4196.45 MB, heapUsed: 4163.29 MB
<--- Last few GCs --->
[28033:0x140008000] 17968 ms: Mark-sweep 4003.2 (4036.4) -> 4003.1 (4036.4) MB, 2233.8 / 0.0 ms (average mu = 0.565, current mu = 0.310) allocation failure scavenge might not succeed
[28033:0x140008000] 19815 ms: Mark-sweep 4163.3 (4196.5) -> 4163.1 (4196.5) MB, 1780.3 / 0.0 ms (average mu = 0.413, current mu = 0.036) allocation failure scavenge might not succeed
<--- JS stacktrace --->
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
...
Es sollte besonders darauf geachtet werden, Buffer nicht zum Testen zu verwenden.Da Buffer ein für Node.js einzigartiges Binärobjekt ist, wird es von Node.js separat mit C++ implementiert. Es reserviert keinen Speicher über V8 und gehört zum Off-Heap-Speicher. 🎜🎜Der Computer, den ich verwende, ist das MacBook Pro M1 Pro, die Node.js-Version ist
v16.17.0
und die verwendete V8-Version ist 9.4.146.26-node.22 (über Prozess. versionen.v8 erhalten). 🎜🎜Das Ausgabeergebnis ist (einige redundante Informationen werden weggelassen): 🎜rrreee🎜Es ist ersichtlich, dass das Speicherlimit nach 4000 MB überschritten wird, ein Heap-Überlauf auftritt und der Prozess dann beendet wird. Beachten Sie, dass auf meinem Computer der standardmäßige maximale Speicher 4 GB beträgt. 🎜🎜Der tatsächliche maximale Speicher hängt von der Maschine ab, auf der er ausgeführt wird. Wenn die Speichergröße Ihrer Maschine 2 GB beträgt, wird der maximale Speicher auf 1,5 GB eingestellt. 🎜🎜Weitere Informationen zu Knoten finden Sie unter: 🎜nodejs-Tutorial🎜! 🎜Das obige ist der detaillierte Inhalt vonLassen Sie uns über den GC-Mechanismus (Garbage Collection) in Node.js sprechen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!