10 Punkte von GN⁺ 2025-08-05 | Noch keine Kommentare. | Auf WhatsApp teilen
  • In der V8-Engine wurde die Performance der Funktion JSON.stringify um mehr als das Doppelte gesteigert, was die Geschwindigkeit der Datenserialisierung verbessert
  • Durch die Einführung eines Optimierungspfads für Objekte ohne Seiteneffekte konnten viele defensive Prüfungen übersprungen werden, was bei typischen Datenobjekten zu großen Geschwindigkeitsgewinnen führt
  • Bei der String-Verarbeitung kamen fortgeschrittene Verfahren für Hardware und Speicher zum Einsatz, darunter die Unterscheidung zwischen 1-Byte-/2-Byte-Zeichen, die Nutzung von SIMD und Änderungen an der Struktur temporärer Puffer
  • Beim Zahlenumwandlungsprozess wurde der bisherige Grisu3-Algorithmus durch Dragonbox ersetzt, was auch bei Aufrufen von Number.toString() insgesamt schnellere Konvertierungen ermöglicht
  • Bei einigen Argumenten und Formen wird zwar zum allgemeinen Serialisierungspfad zurückgekehrt, aber in den meisten Webentwicklungs-Szenarien profitiert man automatisch von der Optimierung

Überblick

  • JSON.stringify ist eine Schlüsselfunktion zum Umwandeln von Daten in Strings in JavaScript
  • Eine Leistungssteigerung dieser Funktion wirkt sich auch positiv auf sehr wichtige Web-Aufgaben wie Netzwerkanfragen oder das Speichern in localStorage aus
  • Durch aktuelles V8-Engineering wurde die Geschwindigkeit dieser Funktion um mehr als das Doppelte verbessert, und die wichtigsten Optimierungsansätze werden im Detail vorgestellt

Fast-Path für Seiteneffektfreiheit

  • Der Kern der Optimierung ist die Anwendung eines schnellen Serialisierungspfads, der nur in Situationen ohne Seiteneffekte (side effects) verwendet werden kann
  • In solchen Fällen werden Objekte nicht rekursiv, sondern mit einer iterativen Struktur durchlaufen, wodurch keine Stack-Overflow-Prüfungen nötig sind und auch tiefere Objekte serialisiert werden können
  • Wenn ein Datenobjekt einfach ist, nutzt V8 statt der langsamen allgemeinen Logik diesen Fast Path, lässt viele Prüfungen aus und erhöht so die Geschwindigkeit

Umgang mit verschiedenen String-Darstellungen

  • V8 speichert Strings je nach 1-Byte-/2-Byte-Zeichen (ASCII/Nicht-ASCII) unterschiedlich; sobald auch nur ein Nicht-ASCII-Zeichen enthalten ist, wird der gesamte String als 2-Byte-String behandelt
  • Für die Performance der String-Serialisierung werden separate Algorithmus-Versionen je nach String-Typ kompiliert
  • Da während der Verarbeitung der Typ der String-Instanz geprüft werden muss, übernimmt bei Erkennung eines 2-Byte-Strings ein passender 2-Byte-Serializer den Zustand
  • Dadurch gibt es praktisch keinen Overhead durch Pfadwechsel je nach String-Encoding
  • Das Ergebnis wird erzeugt, indem zunächst getrennte 1-Byte- und 2-Byte-Puffer erstellt und am Ende einfach zusammengeführt werden

Optimierung der String-Serialisierung mit SIMD

  • JavaScript-Strings können Zeichen enthalten, die bei der JSON-Serialisierung maskiert werden müssen
  • Lange Strings werden mit SIMD-Hardwarebefehlen (wie ARM64 Neon) geprüft, sodass mehrere Bytes gleichzeitig verarbeitet werden
  • Kurze Strings werden mit der SWAR-Methode verarbeitet, bei der per Bit-Operationen in allgemeinen Registern mehrere Zeichen gleichzeitig behandelt werden
  • Unabhängig von der Methode kann in den meisten Fällen der gesamte String ohne besondere Umwandlung schnell kopiert werden

Express Lane hinzugefügt

  • Selbst innerhalb des Fast Path wurde eine Express Lane eingerichtet, damit die Serialisierung allein durch das Kopieren von Schlüsseln ohne wiederholte Arbeiten wie Property-Prüfungen möglich ist
  • Mithilfe des Hidden-Class-Flags eines Objekts werden Fälle, in denen Schlüssel keine Symbols enthalten, alle enumerable sind und ohne Escaping serialisiert werden können, als fast-json-iterable markiert
  • Wird später ein anderes Objekt mit derselben Hidden Class serialisiert, können die Schlüssel sofort ohne zusätzliche Prüfung kopiert werden
  • Diese Technik wird auch in JSON.parse für schnelle Schlüsselvergleiche eingesetzt

Schnellerer double-to-string-Algorithmus

  • Auch die Umwandlung von Zahlen in Strings ist häufig und komplex
  • Durch den Austausch des bisherigen Grisu3-Algorithmus gegen Dragonbox ergeben sich Leistungsverbesserungen auch bei sämtlichen Aufrufen von Number.prototype.toString()

Optimierung der Struktur temporärer Puffer

  • Beim Erzeugen von Strings wurde bisher ein einzelner zusammenhängender Puffer verwendet, was bei Platzmangel zu dem Overhead führte, den gesamten Inhalt kopieren zu müssen
  • Die neue Methode verwendet eine segmentierte Pufferstruktur, bei der je nach Bedarf mehrere kleinere Puffer aneinandergereiht werden
  • Dadurch muss bei Platzmangel nicht mehr alles kopiert werden, sondern nur ein neuer Puffer allokiert werden

Grenzen

  • Der Fast Path funktioniert nur bei einfacher Datenserialisierung
  • Werden die folgenden Bedingungen nicht erfüllt, wird der allgemeine Pfad verwendet
    • replacer- oder space-Argumente dürfen nicht verwendet werden (kein Pretty-Print, keine Transformation)
    • Es muss sich um ein einfaches Objekt ohne benutzerdefinierte toJSON-Methode handeln
    • Bei indexbasierten Properties wird auf den langsamen Pfad gewechselt
    • ConsString und andere spezielle Strings werden nicht verarbeitet
  • Für die meisten üblichen Einsatzfälle wie Datenserialisierung, API-Antworten oder Konfigurations-Caching greift die Optimierung automatisch

Fazit

  • Durch eine Neugestaltung des Ansatzes in allen Bereichen – von der Grundarchitektur von JSON.stringify über Speicherverarbeitung bis zur Zeichenverarbeitung – wurde im JetStream2-Benchmark eine mehr als doppelte Geschwindigkeitssteigerung erzielt
  • Diese Verbesserungen sind ab V8 Version 13.8 (Chrome 138) direkt nutzbar

Noch keine Kommentare.

Noch keine Kommentare.