MemLab – Ein Blick auf das neue JavaScript-Framework von Meta zur Verringerung von Memory Leaks

26.01.2023

Was ist Memlab und wozu wurde es entwickelt?

MemLab ist ein End-to-End-Test- und Analyse-Framework zur Identifizierung von JavaScript-Speicherlecks und Optimierungsmöglichkeiten.

Das Unternehmen Meta entwickelte das Framework, um unter anderem die Zeit und den Aufwand für die Messung, Optimierung und Steuerung von Anwendungs- und Interaktionsladezeiten zu reduzieren. Damit konnte der Techgigant bei der allseits bekannten Webseite „Facebook.com“ die „Out of Memory“-Crashes um 50 % reduzieren. Im Jahr 2022 veröffentlichte Meta das Framework als Open-Source-Projekt (MIT-Lizenz) [1].

Welche Funktionen bietet MemLab?

  • Erfassung von Memory-Leak Mustern: MemLab kann Memory-Leak-Muster in JavaScript-Anwendungen erfassen und speichern, um sie später für Tests und Überwachungen zu verwenden.
  • Aggregieren und Gruppieren ähnlicher Speicherlecks
  • Im Browser interagieren und JavaScript-Heap-Snapshots erstellen
  • Heap-Snapshots analysieren und Speicherlecks herausfiltern
  • Objektorientierte Heap-Traversing-API – Unterstützt die Erstellung von selbst definierten Speicherleck-Detektoren und ermöglicht die programmatische Analyse von JS-Heap-Snapshots, die von Chromium-basierten Browsern, Node.js, Electron.js und Hermes erstellt wurden
  • Memory-CLI-Toolbox – Eingebaute Toolbox und APIs zum Auffinden von Speicheroptimierungsmöglichkeiten (nicht unbedingt nur Speicherlecks)
  • Erstellung von End-to-end Tests: MemLab ermöglicht es, Tests zur Überprüfung der Memory-Leak-Sicherheit einer Anwendung zu erstellen.
  • Memory Assertions in Node.js – Ermöglicht Unit-Tests oder laufenden Node.js-Programmen, einen Heap-Snapshot des eigenen Zustands zu erstellen, eine Selbstkontrolle des Speichers durchzuführen oder erweiterte Memory Assertions zu schreiben [2]

Wo kann MemLab eingesetzt werden?

MemLab unterstützt JavaScript und TypeScript Anwendungen. Neben der JavaScript-Laufzeitumgebung Node.js werden zudem Single-Page-Applications mit dem Frontend-Framework React unterstützt.

Das Framework lässt sich ebenso in eine CI-Pipeline integrieren, um regelmäßige automatisierte end-to-end Tests für eine Anwendung durchlaufen zu lassen und auf Memory leaks zu prüfen:

(MemLab Konsolenbefehl, Quelle: https://facebook.github.io/memlab/docs/guides/guides-detached-dom)

Unter der Haube wird dabei das End-to-End-Testing Framework anhand einer Puppeteer API durchgeführt, lässt sich aber auch in existierende Testing-frameworks integrieren [3].

MemLab: Test anhand von Anforderungen

Um MemLab auf die Probe zu stellen, wird ein kleines Beispiel durchgeführt. Hierfür wird ein Beispielprojekt von Meta herangezogen. Für dieses Beispiel wird MemLab folgenden Anforderungen entgegengestellt:

  • Memory Leaks in Form von Detached DOM-Elementen sollen erkannt werden
  • JavaScript-Objekte in erheblicher Größe sollen erkannt und auf diese hingewiesen werden

Detached DOM-Elemente sind HTML-Elemente, die aus der DOM entfernt wurden, aber deren Speicher aufgrund von JavaScript erhalten bleibt.

Einrichtung eines Beispiels

Das folgende Beispielprojekt wird von dieser Git-URL geklont und lokal gebaut (npm i && npm run build):

https://github.com/facebook/memlab.git

(Das Build Skript ‚npm run build‘ von Meta warf einen Fehler aus, der nach kurzer Recherche mit Schwierigkeiten des „rm“ – Befehls auf Windows Betriebssystemen zurückführt. Im Rahmen des Beispiels kann man den Fehler ausweichen, indem man den Befehl „npm run clean“ weglässt und stattdessen den Befehl „npm run build-pck –workspaces“ manuell ausführt. Eine Alternative wäre die Installation eines Node Packages, das den Fehler behebt – im Rahmen des Beispiels wird jedoch davon abgesehen)

Im Pfad packages/e2e/static/example des Beispiels, kann mit dem Befehl „npm run dev“ eine Entwicklungsinstanz hochgefahren werden, die über den Browser unter „localhost:3000“ erreichbar ist:

(Screenshot aus dem MemLab Beispiel, Quelle: MemLab Beispielprojekt)

Erkennung von Memory Leaks

In der oben abgebildeten Anwendung wird mit einem Klick auf den Button eine Funktion aufgerufen, um Memory Leaks durch die Erstellung sämtlicher DIV-Elemente zu erzeugen:

(MemLab Detached-DOMS Beispiel, Quelle: Eigener Screenshot)

Um die App von MemLabs nach Memory Leaks suchen zu lassen, muss erstmal ein Szenario definiert werden:

In dieser Datei wird die URL für ein Szenario und eine Reihe von Interaktionen angegeben, bei denen von MemLab geprüft werden soll, ob es innerhalb diesen zu einem Memory Leak kam. In diesem Fall soll die URL der Beispielanwendung zurückgegeben werden und auf den Button geklickt werden, um eine Menge von Detached DOM-Elements in Form von zahlreichen DIV-Elementen zu erstellen:

(MemLab Szenario Beispiel, Quelle: https://facebook.github.io/memlab/docs/guides/guides-detached-dom)

Somit kann MemLab das Szenario nun durchlaufen und auf Memory Leaks überprüfen. Um diesen Prozess durchzuführen, muss folgender Befehl ausgeführt werden:

memlab run --scenario ~/memlab/scenarios/detached-dom.js

In der Konsole startet der Durchlauf. Wie bei End-to-end Tests durchläuft MemLab das zuvor definierte Szenario. Erst die Navigation auf die Anwendung, dann der Klick auf den Button. Eine Konsolenausgabe am Ende des Durchlaufs visualisiert wichtige Kennzahlen im Hinblick auf Memory Leaks:

(MemLab Scenario Konsolenausgabe, Quelle: https://facebook.github.io/memlab/docs/guides/guides-detached-dom)

1: Hier wird die Größe des Heaps beim initialen Seitenaufruf bis zum Endzustand des Durchlaufs dargestellt

2: Hier wird die Anzahl ähnlicher Leaks und die Speichergröße des gesamt unbeabsichtigt freigegeben Speichers abgebildet

3: Hier bildet MemLab eine Aufzeichnung von Aktionen und Events, die zum Leak geführt haben. Damit kann der Entwickler besser nachvollziehen, zu welchem Zeitpunkt ein Memory Leak entsteht

Die zuvor hinzugefügten „leakedObjects“ werden mit aufgeführt und damit erkannt.

Erkennung von großen JavaScript-Objekten

Hierzu wird eine ähnliche kleine Anwendung erstellt, die bei einem Seitenaufruf eine Array-Liste mit über eine Million Einträgen erstellt:

(MemLab Oversized Objects Beispiel, Quelle: Eigener Abzug)

Auch hierzu wird ein Szenario für MemLab erstellt, das die Seite aufruft und wieder wegnavigiert, sodass ein Start- und Endzustand ermittelt werden kann. Da MemLab von Haus aus keine übergroßen Objekte explizit auflistet, muss zu diesem Zweck ein Filter definiert werden, der alle Objekte, die über eine bestimmte Größe hinausragen, als Leak angezeigt werden. Das ist nur ein Beispiel (leakFilter) für benutzerdefinierte Filter, die je nach Belieben für einen Durchgang definiert werden können:

(MemLab Oversized Object Beispiel, Quelle: https://facebook.github.io/memlab/docs/guides/guides-detect-oversized-object)

Nun kann das Szenario mit folgendem Befehl durchgeführt werden:

memlab run --scenario ~/memlab/scenarios/oversized-object-with-filter.js

Konsolenausgabe:

(MemLab Oversized Object with leak filter Beispiel, Quelle: Eigener Auszug)

Wäre der Filter nicht im Szenario definiert worden, würde MemLab kein Leak ausgeben. So können wir unten im Trace nachvollziehen, dass die Array-Liste namens „bigArray“ mit dem Leak zusammenhängt.

Fazit 

Die oben gestellten Anforderungen konnte MemLab erfüllen und macht insgesamt den Eindruck ein ziemlich hilfreiches Framework für die Analyse und Optimierung einer Anwendung zu sein.

Sollte MemLab in Projekten mit einbezogen werden?

In Anbetracht der Funktionen in den Beispielen ist es wichtig zu erwähnen, dass MemLab weitaus mehr zu bieten hat (siehe obige Liste). Vor allem für die Integration in den Entwicklungsprozess bietet MemLab Automatismen, die die Zeit und den Aufwand für derartige Analysen erspart. Ein Beispiel ist das automatische Aufnehmen und Abspeichern von Screenshots, auf denen Durchlaufergebnisse dargestellt sind. Bei Anwendungen, die mit MemLab kompatibel sind und mit Speicher- oder Ladezeitproblemen zu kämpfen haben, wirkt das Framework ziemlich unterstützend. Jedoch könnte MemLab auch große Gefahren mit sich ziehen:

Die Nutzung von MemLab in Kombination mit anderen Frameworks ist bisher kaum oder nicht dokumentiert. MemLab wurde im Jahr 2022 veröffentlicht und wirft aufgrund seiner Neuheit viele offene Fragen auf. Darunter auch die Kompatibilität mit anderen Sprachen und Frameworks. Ein Beispiel dafür ist die Nutzung mit dem Frontend-Framework Vue.js. Bisher ist dieses nicht offiziell kompatibel. Dennoch kann dies mit eigenem Aufwand, wie zum Beispiel das Überschreiben von Funktionen, ermöglicht werden [4]. Auch die Nutzung anderer Testing-Frameworks wie Playwright von Microsoft ist wohl über zusätzliche Schritte möglich [5].

Sollte es zu Problemen kommen, finden sich im Internet kaum Ergebnisse, die sich auf dieses Framework beziehen. Damit ist man bei Problemfällen zu einem sehr großen Teil von der offiziellen Dokumentation oder den Entwicklern abhängig.

Meta veröffentlicht 2-3 neue Versionen des Frameworks im Monat [6]. Dies deutet darauf hin, dass an dem Framework aktiv entwickelt und gepflegt wird. Empfehlenswert zum aktuellen Entwicklungsstand ist es, MemLab mit Vorsicht zu genießen.

 

Quellenangabe:

[1]: https://engineering.fb.com/2022/09/12/open-source/memlab/

[2] https://github.com/facebook/memlab

[3] https://github.com/facebook/memlab/issues/37

[4] https://github.com/facebook/memlab/issues/35

[5] https://facebook.github.io/memlab/docs/intro

[6] https://www.npmjs.com/package/memlab/v/1.1.13?activeTab=versions

Zurück zur Übersicht

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

*Pflichtfelder

*