Speicher und Garbage Collector in TypeScript: Was verbirgt sich hinter den Kulissen?
\n\nStellen Sie sich vor, Sie bauen ein Haus. Sie kaufen Ziegel, Zement, Bewehrungsstahl – aber wenn Sie den Bauschutt nicht wegräumen, wird die Baustelle bald zu einer Müllhalde. Dasselbe passiert in Ihrem TypeScript-Code. Sie erstellen Objekte, Arrays, Closures – und wenn Sie den Speicher nicht rechtzeitig freigeben, wird die Anwendung langsamer und stürzt schließlich mit einem Out of Memory-Fehler ab.
In diesem Artikel analysieren wir, wie die Speicherverwaltung in TypeScript und ihr wichtigstes Werkzeug – der Garbage Collector – funktionieren. Sie erfahren, welche Mechanismen hinter der Speicherfreigabe stecken, wie Sie Lecks vermeiden und warum Ihr Code auch dann noch Megabyte „fressen“ kann, wenn Sie ihn nicht mehr verwenden.
\n\nLos geht's!
\n\nWie verwaltet TypeScript den Speicher? Grundlagen
\n\nBeginnen wir mit einem wichtigen Punkt: TypeScript ist keine eigenständige Sprache, sondern ein Aufsatz auf JavaScript. Das bedeutet, dass Speicher und Garbage Collector in TypeScript genauso funktionieren wie in JavaScript. TypeScript fügt keine neuen Mechanismen zur Speicherverwaltung hinzu, gibt uns aber Werkzeuge (Typen, Interfaces), um sichereren Code zu schreiben.
\n\nIn JavaScript wird der Speicher in zwei Hauptbereiche unterteilt:
\n\n- \n
- Stack – speichert primitive Datentypen (Zahlen, Zeichenketten, boolesche Werte) und Referenzen auf Objekte. Wird automatisch freigegeben, wenn eine Funktion verlassen wird. \n
- Heap – speichert Objekte, Arrays, Funktionen. Hier arbeitet der Garbage Collector. \n
Wenn Sie schreiben:
\n\nconst user = { name: 'Alice', age: 30 };\n\nDie Variable user wird im Stack gespeichert und enthält eine Referenz auf das Objekt im Heap. Solange es eine Referenz gibt, lebt das Objekt. Sobald die Referenz verschwindet, wird das Objekt zu „Müll“.
Der Garbage Collector in TypeScript: Wie funktioniert er?
\n\nDer Garbage Collector (GC) ist ein automatischer Prozess, der Objekte findet, auf die es keine Referenzen mehr gibt, und den von ihnen belegten Speicher freigibt. Moderne Engines (V8 in Chrome, SpiderMonkey in Firefox) verwenden komplexe Algorithmen, aber die Grundlage ist der Mark-and-Sweep-Algorithmus.
\n\nSo funktioniert es:
\n\n- \n
- Der GC beginnt mit den „Wurzeln“ – globalen Objekten, lokalen Variablen in aktuell ausgeführten Funktionen. \n
- Er durchläuft alle Referenzen von den Wurzeln aus und markiert jedes erreichbare Objekt. \n
- Alle nicht markierten Objekte gelten als Müll und werden entfernt. \n
Klingt einfach, aber in der Praxis gibt es Nuancen. Zum Beispiel zirkuläre Referenzen:
\n\nfunction createCycle() {\n const obj1: any = {};\n const obj2: any = {};\n obj1.ref = obj2;\n obj2.ref = obj1;\n return 'done';\n}\n\nFrüher führten solche Strukturen zu Lecks, aber moderne Garbage Collector kommen mit Zyklen gut zurecht – Hauptsache, beide Objekte sind von den Wurzeln aus nicht mehr erreichbar.
\n\nTypische Speicherlecks in TypeScript-Anwendungen
\n\nAuch mit einem intelligenten Garbage Collector kann man „ins Fettnäpfchen treten“. Hier sind die häufigsten Szenarien, die zu Speicherlecks in TypeScript führen:
\n\n1. Vergessene Timer und Event-Handler
\n\nEine der häufigsten Ursachen. Sie haben ein Ereignis abonniert, aber vergessen, es zu kündigen:
\n\nclass TimerComponent {\n private intervalId: number;\n\n start() {\n this.intervalId = window.setInterval(() => {\n console.log('Tick');\n }, 1000);\n }\n\n // Vergessen, stop() aufzurufen – der Timer wird ewig leben!\n}\n\nLösung: Bereinigen Sie immer Timer und melden Sie sich von Ereignissen in der Methode dispose oder ngOnDestroy (für Angular) ab.
2. Closures, die Referenzen halten
\n\nClosures sind ein mächtiges Werkzeug, können aber versehentlich große Objekte festhalten:
\n\nfunction createHeavyClosure() {\n const hugeData = new Array(1000