Heim > Web-Frontend > js-Tutorial > Eine kurze Analyse des Speicherverlustproblems in Node.js_node.js

Eine kurze Analyse des Speicherverlustproblems in Node.js_node.js

WBOY
Freigeben: 2016-05-16 15:53:19
Original
1126 Leute haben es durchsucht

Dieser Artikel ist der erste einer Reihe von A Node.JS Holiday Season-Artikeln, die Ihnen vom Identity-Team von Mozilla präsentiert wurden, das letzten Monat die erste Beta-Version von Persona veröffentlicht hat. Bei der Entwicklung von Persona haben wir eine Reihe von Tools entwickelt, vom Debuggen über die Lokalisierung bis hin zum Abhängigkeitsmanagement und mehr. In dieser Artikelserie werden wir unsere Erfahrungen und diese Tools mit der Community teilen, die für jeden nützlich sein werden, der mit Node.js einen Hochverfügbarkeitsdienst aufbauen möchte. Wir hoffen, dass Ihnen diese Artikel gefallen und freuen uns auf Ihre Gedanken und Beiträge.

Wir beginnen mit einem aktuellen Artikel über ein wesentliches Problem in Node.js: Speicherlecks. Wir stellen Node-Memwatch vor – eine Bibliothek, die dabei hilft, Speicherlecks in Node zu finden und zu isolieren.


Warum verlangst du Ärger?

Die am häufigsten gestellte Frage zum Verfolgen von Speicherlecks lautet: „Warum sollten Sie sich die Mühe machen?“ Gibt es nicht dringendere Probleme, die zuerst angegangen werden müssen? Warum entscheiden Sie sich nicht dafür, den Dienst von Zeit zu Zeit neu zu starten oder ihm mehr RAM zuzuweisen? Um diese Fragen zu beantworten, schlagen wir die folgenden drei Vorschläge vor:

1. Vielleicht interessiert Sie der wachsende Speicherbedarf nicht, aber V8 schon (V8 ist die Engine der Node-Laufzeit). Mit zunehmenden Speicherlecks geht V8 aggressiver mit dem Garbage Collector um, was dazu führen kann, dass Ihre Anwendung langsamer ausgeführt wird. Daher beeinträchtigen Speicherlecks auf dem Knoten die Programmleistung.

2. Speicherlecks können andere Arten von Fehlern auslösen. Code, der Speicher verliert, verweist möglicherweise ständig auf begrenzte Ressourcen. Es könnte sein, dass Ihnen die Dateideskriptoren ausgehen und Sie möglicherweise plötzlich keine neuen Datenbankverbindungen mehr herstellen können. Diese Art von Problem kann auftreten, lange bevor Ihrer App der Speicher ausgeht, aber es kann trotzdem zu Problemen führen.

3. Irgendwann wird Ihre App früher oder später abstürzen, und das wird auf jeden Fall passieren, wenn Ihre App immer beliebter wird. Auf Hacker News wird jeder über Sie lachen und sich lächerlich machen, was Sie zu einer Tragödie machen wird.

Wo ist das Ameisennest, das die Böschung von Tausenden von Kilometern durchbrochen hat?

Beim Erstellen komplexer Anwendungen kann es an vielen Stellen zu Speicherverlusten kommen. Schließungen sind wohl die bekanntesten und berüchtigtsten. Da Abschlüsse Verweise auf Dinge innerhalb ihres Gültigkeitsbereichs behalten, kommt es normalerweise zu Speicherlecks.

Verschlusslecks werden oft erst entdeckt, wenn jemand danach sucht. Aber in der asynchronen Welt von Node generieren wir jederzeit und überall ständig Abschlüsse durch Rückruffunktionen. Wenn diese Rückruffunktionen nicht unmittelbar nach der Erstellung verwendet werden, wächst der zugewiesene Speicher weiter und Code, der scheinbar keine Speicherlecks aufweist, tritt aus. Und ein solches Problem ist schwieriger zu finden.

Ihre Anwendung kann aufgrund von Problemen im Upstream-Code auch Speicherverluste verursachen. Vielleicht können Sie den Code finden, der den Speicherverlust verursacht hat, aber vielleicht starren Sie einfach nur auf Ihren perfekten Code und fragen sich, wie er verloren gegangen ist!


Es sind diese schwer zu lokalisierenden Speicherlecks, die uns dazu bringen, ein Tool wie Node-Memwatch zu wollen. Der Legende nach schloss sich unser eigener Lloyd Hilaiel vor ein paar Monaten zwei Tage lang in einem kleinen Raum ein, um einen Speicherverlust aufzuspüren, der bei Stresstests offensichtlich wurde. (Bleiben Sie übrigens gespannt auf Lloyds kommenden Artikel über Lasttests)

Nach zwei Tagen harter Arbeit entdeckte er schließlich den Übeltäter im Node-Kernel: Der Event-Listener in http.ClientRequest wurde nicht freigegeben. (Der Patch, der das Problem schließlich behob, bestand nur aus zwei, aber entscheidenden Buchstaben). Es war diese schmerzhafte Erfahrung, die Lloyd dazu veranlasste, ein Tool zu schreiben, das dabei helfen könnte, Speicherlecks zu finden.

Tool zum Auffinden von Speicherlecks

Es gibt viele nützliche und sich ständig verbessernde Tools zum Auffinden von Speicherlecks in Node.js-Anwendungen. Hier sind einige davon:

  • node-mtrace von Jimb Esser, das das mtrace-Tool von GCC zur Analyse der Heap-Nutzung verwendet.
  • Dave Pachecos node-heap-dump erstellt einen Schnappschuss des V8-Heaps und serialisiert alles in einer riesigen JSON-Datei. Es enthält auch JavaScript-Tools zur Analyse von Studien-Snapshot-Ergebnissen.
  • Danny Coates‘ v8-profiler und node-inspector bieten einen in Node gebündelten V8-Profiler und eine Debug-Schnittstelle basierend auf WebKit Web Inspector.
  • Felix Gnass‘ deaktiviert den Keeper-Chart-Zweig nicht.
  • Felix Geisendorfers Node Memory Leak Tutorial ist ein kurzes und cooles Tutorial zur Verwendung von v8-Profiler und Node-Debugger. Es ist auch das fortschrittlichste technische Handbuch zum Debuggen von Node.js-Speicherlecks.
  • Joyents SmartOS-Plattform, die eine große Anzahl von Tools zum Debuggen von Node.js-Speicherlecks bereitstellt.

Wir alle mögen die oben genannten Tools, aber keines davon trifft auf unser Szenario zu. Web Inspector eignet sich hervorragend zum Entwickeln von Anwendungen, ist jedoch in Hot-Deployment-Szenarien schwierig zu verwenden, insbesondere wenn mehrere Server und Unterprozesse beteiligt sind. Ebenso sind Speicherlecks, die bei langfristigen Hochlastvorgängen auftreten, schwer zu reproduzieren. Tools wie dtrace und libumem sind zwar beeindruckend, aber nicht auf allen Betriebssystemen verfügbar.

Enternode-memwatch

Wir benötigen eine plattformübergreifende Debugging-Bibliothek, die nicht erfordert, dass das Gerät uns mitteilt, wann unser Programm möglicherweise einen Speicherverlust aufweist, und die uns dabei hilft, herauszufinden, wo der Verlust vorliegt. Also haben wir Node-Memwatch implementiert.

Es versorgt uns mit drei Dingen:

Ein „Leck“-Ereignissemitter
 

   memwatch.on('leak', function(info) {
  // look at info to find out about what might be leaking
  });
Nach dem Login kopieren

Ein Statusereignis-Emitter

       

  var memwatch = require('memwatch');
  memwatch.on('stats', function(stats) {
  // do something with post-gc memory usage stats
  });
Nach dem Login kopieren

Eine Heap-Speicherbereichsklassifizierung

  var hd = new memwatch.HeapDiff();
  // your code here ...
  var diff = hd.end();
Nach dem Login kopieren

Und es gibt auch eine Funktion, die den Garbage Collector auslösen kann, was beim Testen sehr nützlich ist. Okay, insgesamt vier.
 

 var stats = memwatch.gc();
Nach dem Login kopieren

memwatch.on('stats', ...): Post-GC-Heap-Statistik

node-memwatch kann nach einer vollständigen Speicherbereinigung und Speicherkomprimierung ein Beispiel für die Speichernutzung ausgeben, bevor ein JS-Objekt zugewiesen wird. (Es verwendet den Post-GC-Hook von V8, V8::AddGCEpilogueCallback, um jedes Mal, wenn eine Garbage Collection ausgelöst wird, Informationen zur Heap-Nutzung zu sammeln.)

Zu den Statistiken gehören:

  • uses_trend (Nutzungstrend)
  • current_base (aktuelle Basis)
  • geschätzte_Basis (erwartete Basis)
  • num_full_gc (Anzahl der vollständigen Garbage Collections)
  • num_inc_gc (erhöhte Anzahl von Garbage Collections)
  • heap_compactions (Anzahl der Speicherkomprimierungen)
  • min (Minimum)
  • max (maximal)

Hier ist ein Beispiel dafür, wie die Daten für eine Anwendung mit einem Speicherverlust aussehen. Das folgende Diagramm zeigt die Speichernutzung im Zeitverlauf. Die verrückte grüne Linie zeigt, was Process.memoryUsage() meldet. Die rote Linie zeigt die von node_memwatch gemeldete current_base. Das Feld unten links zeigt zusätzliche Informationen.

2015623152204606.png (572×441)

Beachten Sie, dass die Incr-GCs sehr hoch sind. Das bedeutet, dass V8 verzweifelt versucht, den Speicher zu löschen.

memwatch.on('leak', ...): Heap-Zuteilungstrend

Wir haben einen einfachen Erkennungsalgorithmus definiert, um Sie darauf aufmerksam zu machen, dass Ihre Anwendung möglicherweise einen Speicherverlust aufweist. Das heißt, wenn nach fünf aufeinanderfolgenden GCs der Speicher immer noch zugewiesen, aber nicht freigegeben ist, gibt Node-Memwatch ein Leak-Ereignis aus. Das spezifische Informationsformat der Veranstaltung ist klar und leicht lesbar, etwa so:

{ start: Fri, 29 Jun 2012 14:12:13 GMT,
 end: Fri, 29 Jun 2012 14:12:33 GMT,
 growth: 67984,
 reason: 'heap growth over 5 consecutive GCs (20s) - 11.67 mb/hr' }
Nach dem Login kopieren

memwatch.HeapDiff(): 查找泄漏元凶

最后,node-memwatch能比较堆上对象的名称和分配数量的快照,其对比前后的差异可以帮助找出导致内存泄漏的元凶。

var hd = new memwatch.HeapDiff();
 
// Your code here ...
 
var diff = hd.end();
Nach dem Login kopieren

对比产生的内容就像这样:

{
 "before": {
  "nodes": 11625,
  "size_bytes": 1869904,
  "size": "1.78 mb"
 },
 "after": {
  "nodes": 21435,
  "size_bytes": 2119136,
  "size": "2.02 mb"
 },
 "change": {
  "size_bytes": 249232,
  "size": "243.39 kb",
  "freed_nodes": 197,
  "allocated_nodes": 10007,
  "details": [
   {
    "what": "Array",
    "size_bytes": 66688,
    "size": "65.13 kb",
    "+": 4,
    "-": 78
   },
   {
    "what": "Code",
    "size_bytes": -55296,
    "size": "-54 kb",
    "+": 1,
    "-": 57
   },
   {
    "what": "LeakingClass",
    "size_bytes": 239952,
    "size": "234.33 kb",
    "+": 9998,
    "-": 0
   },
   {
    "what": "String",
    "size_bytes": -2120,
    "size": "-2.07 kb",
    "+": 3,
    "-": 62
   }
  ]
 }
}
Nach dem Login kopieren

HeapDiff方法在进行数据采样前会先进行一次完整的垃圾回收,以使得到的数据不会充满太多无用的信息。memwatch的事件处理会忽略掉由HeapDiff触发的垃圾回收事件,所以在stats事件的监听回调函数中你可以安全地调用HeapDiff方法。

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage