Fortschritte bei der Leistungsfähigkeit von JavaScript in IE10 und Windows 8

IEBlog Deutsch

Blog des Internet Explorer-Entwicklerteams

Fortschritte bei der Leistungsfähigkeit von JavaScript in IE10 und Windows 8

  • Comments 0

Am Donnerstag, den 31. Mai 2012, haben wir die Windows 8 Release Preview und die sechste IE10 Plattform Preview präsentiert. Unter Windows 8 ist ein HTML5-Browsermodul integriert, das zwei unterschiedliche Benutzeroberflächen (Metro-Stil und Desktop), sowie Apps im Metro-Stil unterstützt, die HTML5 und JavaScript verwenden. Für die Release Preview wurde das moderne JavaScript-Modul Chakra, das erstmals in IE9 verwendet wurde, umfassend überarbeitet. Mit jeder Plattform Preview verfolgen wir weiter unser Ziel, ein Modul zu erstellen, das hervorragende Leistung im Internet bietet und gleichzeitig kompatibel, interoperabel und sicher ist. In diesem Beitrag werden die Verbesserungen des JavaScript-Moduls vorgestellt, mit denen in neuen Webanwendungsszenarien hervorragende Leistungen ermöglicht werden.

Leistung für echte Webanwendungen

Webanwendungen haben sich innerhalb der letzten Jahre rasant entwickelt. Noch vor zehn Jahren bestand das Internet hauptsächlich aus Websites mit statischem Inhalt, wie z. B. bei einem Blog, der Angebotsseite eines kleinen Unternehmens oder bei Wikipedia. Dank AJAX verbreiteten sich komplexere und interaktive Websites wie z. B. Facebook oder JetSetter. Durch weitere Leistungsfortschritte konnten große und komplexe Anwendungen erstellt werden, z B. Office 365, Bing Maps usw. Die Ausweitung der Standard-W3C-APIs, Leistungssteigerungen bei JavaScript und hardwarebeschleunigte Grafik haben sogar die Entwicklung anspruchsvoller Spiele im Internet ermöglicht, wie z. B. Angry Birds, Pirates Love Daisies, Cut The Rope usw.

Graphische Darstellung des Spektrums von Webseiten und ihrer Leistungsmerkmale. Links werden Standardwebseiten dargestellt, deren wichtigstes Leistungsmerkmal die Seitenladezeit ist. Rechts finden Sie Webanwendungen, HTML5-Spiele und Windows 8-Apps im Metro-Stil, in denen sich die Ausführungsgeschwindigkeit von JavaScript, DOM-Interaktionen und beschleunigte Grafiken deutlich auf die Leistung auswirken.

Mit der Weiterentwicklung von Anwendungen verändern sich die Leistungsmerkmale, die die Benutzererfahrung beeinflussen. Bei herkömmlichen Websites bestimmt die anfängliche Ladezeit, wie schnell dem Benutzer die Inhalte der Seite angezeigt werden. Die Leistung interaktiver Websites und großer Webanwendungen wird möglicherweise von der Effizienz der DOM-Vorgänge, der CSS-Verarbeitung und der Bearbeitung umfangreicher interner Status im Speicher bestimmt. HTML5-Spiele sind häufig auf schnelles Canvas-Rendering, schnelle JavaScript-Ausführung und effiziente automatische Speicherbereinigung angewiesen. Die Browserleistungsfähigkeit ist also eine komplexe Herausforderung, bei der die Anforderungen verschiedenster Anwendungen berücksichtigt werden müssen.

In diesem Beitrag konzentrieren wir uns nur auf die Leistungsfähigkeit eines einzigen Browsersubsystems, des JavaScript-Moduls. Durch die jüngsten Leistungsverbesserungen in JavaScript wird das Verhalten vieler Webanwendungen nicht mehr durch die Ausführung von JavaScript eingeschränkt. Andererseits steht die Leistungssteigerung neuen Szenarien gegenüber, die zusätzliche Anforderungen an das JavaScript-Modul stellen. Wir nutzen jede Gelegenheit, Chakra so weiterzuentwickeln, dass es den Leistungsanforderungen JavaScript-intensiver Anwendungen gerecht wird.

Koordinatensystem mit zwei Achsen, in das Screenshots verschiedener Websites eingetragen wurden: Auf der Y-Achse wird die Verwendung anderer Browserkomponenten, auf der X-Achse das Ausmaß der Ausführung von JavaScript angezeigt. Inhaltswebsites werden unten links im Koordinatensystem angezeigt (geringfügigste Verwendung anderer Browserkomponenten und geringfügigste Ausführung von JavaScript). Grafikintensive Spiele wie Angry Birds werden im oberen rechten Bereich angezeigt.
Ausmaß der Leistung von Webanwendungen

Die Funktionsweise von Chakra

Das Chakra JavaScript-Modul basiert seit seiner Einführung in IE9 auf zwei Grundprinzipien, die auch in IE10 weiterhin eine wichtige Rolle spielen:

  • Minimieren der auszuführenden Vorgänge, um eine positive Benutzererfahrung zu ermöglichen. Das bedeutet, dass möglichst viele Vorgänge bis zum letztmöglichen Zeitpunkt hinausgezögert werden und Arbeitsvorgänge generell vermieden bzw. parallel ausgeführt werden, um die Auswirkungen auf die Reaktionsfähigkeit der Anwendung zu verringern.
  • Nutzen der gesamten verfügbaren Hardware. Dies bedeutet, dass alle verfügbaren CPU-Kerne verwendet und ggf. erweiterte spezialisierte CPU-Befehle generiert werden, z. B. Intels SSE2.

Grafik der Verwendung von zwei Prozessorkernen durch das JavaScript-Modul Chakra
Die parallele Architektur von Chakra

Obwohl Chakra nur ein Browsersubsystem von mehreren ist, besteht es selbst aus verschiedenen Komponenten, die bei der Verarbeitung und Ausführung von JavaScript-Code zusammenwirken. Wenn der Browser eine JavaScript-Datei herunterlädt, wird ihr Inhalt an den Parser von Chakra übergeben und auf syntaktische Richtigkeit überprüft. Dies ist der einzige Vorgang, der für die gesamte Datei ausgeführt wird. Die nachfolgenden Schritte werden für jede Funktion einzeln ausgeführt (einschließlich der globalen Funktion). Bevor eine Funktion ausgeführt wird (die globale Funktion wird unmittelbar nach der Analyse ausgeführt), wird durch den Chakra-Parser eine AST-Darstellung (Abstract Syntax Tree, abstrakte Syntaxstruktur) des Codes erstellt und an den Byte-Codegenerator weitergeleitet. Dieser erstellt eine Zwischenform (Bytecode), die für die Ausführung durch den Interpreter (jedoch nicht direkt durch die CPU) geeignet ist. Sowohl der AST-, als auch der Funktionsbytecode bleiben erhalten, damit sie bei weiteren Ausführungen nicht erneut erstellt werden müssen. Dann wird der Interpreter aufgerufen, um die Funktion auszuführen. Während der Ausführung der einzelnen Vorgänge durch den Interpreter werden Informationen über die festgestellten Eingabetypen (ein Profil) gesammelt. Es wird außerdem registriert, wie oft die Funktion aufgerufen wurde.

Wenn die Anzahl der Aufrufe einen bestimmten Schwellenwert erreicht, wird die Funktion vom Interpreter in die Warteschlange für die Kompilierung gesetzt. Im Gegensatz zu anderen Browsern wird der „Just-in-Time“ (JIT)-Compiler von Chakra in einem gesonderten, dedizierten Thread ausgeführt und beeinträchtigt somit nicht die Skriptausführung. Die einzige Aufgabe des Compilers ist es, optimierte Computeranweisungen für jede Funktion in der Kompilierungsschlange zu generieren. Nachdem eine Funktion kompiliert wurde, wird dem Hauptskriptthread die Verfügbarkeit des Computercodes gemeldet. Beim nächsten Aufruf wird der Einstiegspunkt für die Funktion zum neu kompilierten Computercode umgeleitet und die Ausführung direkt auf der CPU fortgesetzt. Hierbei ist zu beachten, dass Funktionen, die nur ein- oder zweimal aufgerufen werden, in der Regel nie kompiliert werden. Dies spart Zeit und Ressourcen.

JavaScript ist eine verwaltete Laufzeit, da der Entwickler die Speicherverwaltung nicht selbst vornimmt. Diese wird regelmäßig von einem automatischen Garbage Collector ausgeführt, mit dem nicht mehr benötigte Objekte gelöscht werden. Chakra verwendet einen konservativen, quasi-generationalen automatischen Garbage Collector mit dem Prinzip „Markieren und Bereinigen“, der die meisten ihrer Vorgänge gleichzeitig in einem dedizierten Thread ausführt. So können Unterbrechungen in der Skriptausführung, die die Benutzerfreundlichkeit beeinträchtigen würden, minimiert werden.

Aufgrund dieser Architektur kann JavaScript-Code von Chakra fast unmittelbar während des Ladens einer Seite ausgeführt werden. In Phasen hoher JavaScript-Aktivität können Vorgänge von Chakra außerdem parallelisiert werden. Dabei können bis zu drei CPU-Kerne genutzt werden, um gleichzeitig Skript auszuführen, zu kompilieren und Speicher zu bereinigen.

Kurze Seitenladezeit

Selbst bei relativ statischen Websites wird häufig JavaScript für Interaktivität, Werbung oder soziale Netzwerkfunktionen verwendet. Laut Steve Souders’ HTTP Archive nimmt der Umfang von JavaScript auf der ersten Million Webseiten, die auf Alexa gelistet werden, konstant zu.

Grafik des Umfangs von JavaScript auf der ersten Million Webseiten, die auf Alexa gelistet werden
Abbildung des Umfangs von JavaScript auf der ersten Million Webseiten, die auf Alexa gelistet werden

Der für diese Websites verwendete JavaScript-Code muss von dem JavaScript-Modul des Browsers verarbeitet werden. Außerdem muss die globale Funktion jeder Skriptdatei ausgeführt werden, bevor der Inhalt vollständig gerendert werden kann. Folglich ist es entscheidend, die auszuführenden Vorgänge in diesem wichtigen Bereich zu minimieren. Der Parser und der Bytecode-Interpreter von Chakra wurden mit genau diesem Ziel entworfen.

Bytecode-Interpreter. JavaScript-Code, der während des Ladens der Seite ausgeführt wird, übernimmt die Initialisierung und das Setup; dies wird nur einmal ausgeführt wird. Um die Gesamtladezeit zu minimieren, muss dieser Code sofort ausgeführt werden, ohne zu warten, bis ein JIT-Compiler den Code verarbeitet hat und Befehle für den Computer ausgibt. Sobald JavaScript-Code in Bytecode übersetzt wurde, wird dieser vom Interpreter ausgeführt. Um die Zeit bis zur erstmaligen Befehlsausführung weiter zu verkürzen, wird Bytecode von Chakra nur für Funktionen verarbeitet und ausgegeben, deren Ausführung durch eine verzögerte Analyse unmittelbar bevorsteht.

Verzögerte Analyse.Grafik des Anteils von ausgeführtem Code auf 11 beliebten Websites. Der Anteil reicht von knapp über 30 % bis knapp über 50 %.Das JSMeter-Projekt von Microsoft Research hat gezeigt, dass durchschnittliche Webseiten nur einen Bruchteil des heruntergeladenen Codes verwenden – in der Regel zwischen 40 % und 50 % (s. Grafik rechts). Der Grund hierfür ist, dass Entwickler oft beliebte JavaScript-Bibliotheken wie jQuery, dojo oder benutzerdefinierte Bibliotheken, wie sie in Office 365 verwendet werden, einfügen. Es wird jedoch nur ein Bruchteil der von der Bibliothek unterstützten Funktionen genutzt.

Um diese Szenarien zu optimieren, wird von Chakra nur die grundlegendste Syntaxanalyse des Quellcodes ausgeführt. Die restliche Arbeit (Erstellen der abstrakten Syntaxstruktur und des Bytecodes) wird jeweils nur dann ausgeführt, wenn der Aufruf der Funktion unmittelbar bevorsteht. Dies verbessert nicht nur die Reaktionsfähigkeit des Browsers beim Laden von Webseiten, sondern reduziert auch den Speicherbedarf.

In IE9 gab es für die verzögerte Analyse von Chakra eine Einschränkung. Bei Funktionen innerhalb anderer Funktionen musste bei der Analyse die einschließende Funktion einbezogen werden. Diese Einschränkung erwies sich als bedeutend, da viele JavaScript-Bibliotheken das sogenannte „Module Pattern” verwenden, bei dem der Großteil des Bibliothekcodes in eine große Funktion eingeschlossen ist, die sofort ausgeführt wird. In IE10 haben wir diese Einschränkung behoben. Die Analyse und die Bytecodeerstellung wird für jede Funktion, die nicht sofort ausgeführt wird, durch Chakra hinausgezögert.

Leistungsverbesserungen bei JavaScript-intensiven Anwendungen

Wie bereits bei IE9 ist auch bei IE10 die Leistungsverbesserung für echte Webanwendungen das Ziel. Allerdings variiert bei Webanwendungen die Abhängigkeit von der JavaScript-Leistung. Daher liegt für die Erläuterung der Verbesserungen in IE10 der Schwerpunkt auf JavaScript-intensiven Anwendungen, bei denen die Verbesserungen von Chakra zu deutlichen Leistungssteigerungen führt. HTML5-Spiele und Simulationen zählen zu diesen JavaScript-intensiven Anwendungen.

Um zu verstehen, welche Leistungsverbesserungen sich am stärksten auf die Benutzerfreundlichkeit auswirken, haben wir zunächst eine Auswahl von beliebten JavaScript-Spielen (u. a. Angry Birds, Cut the Rope oder Tankworld) und JavaScript-Simulationen (z. B. FishIE Tank, HTML5 Fish Bowl, Ball Pool, Particle System) analysiert. Aus unserer Analyse ergaben sich eine Reihe gemeinsamer Charakteristika und Codierungsmuster. Alle diese Anwendungen werden von einem Hochfrequenz-Timer-Rückruf gesteuert. Die meisten verwenden Canvas für das Rendering, andere sind auf die Animation von DOM-Elementen angewiesen und wieder andere verwenden eine Kombination aus beiden Ansätzen. Bei den meisten Anwendungen sind zumindest Teile des Codes in objektorientiertem Stil geschrieben, entweder im Anwendungscode oder in enthaltenen Bibliotheken (z. B. Box2d.js). Kurze Funktionen sind ebenso verbreitet wie regelmäßige Lese- und Schreibzugriffe und Polymorphie. Alle Anwendungen führen Gleitkomma-Arithmetik aus. Einige belegen relativ viel Speicher, sodass sich der Aufwand für den Garbage Collector erhöht. Diese häufigen Muster wurden zum Schwerpunkt bei der Leistungsverbesserung von IE10. In den folgenden Abschnitten werden die vor diesem Hintergrund vorgenommenen Änderungen beschrieben.

Just-in-Time-Compiler: neu entwickelt und verbessert

In IE10 wurden grundlegende Verbesserungen am JIT-Compiler von Chakra vorgenommen. Es werden jetzt zwei zusätzliche Prozessorarchitekturen unterstützt: x64 und ARM. Gleich, ob Ihre JavaScript-Anwendung von einem Benutzer an einem 64-Bit Computer oder an einem ARM-basierten Tablet verwendet wird, kann sie so direkt auf der CPU ausgeführt werden.

Außerdem wurde der grundlegende Ansatz zum Generieren von Computercode geändert. JavaScript ist eine sehr dynamische Sprache, die den Umfang der bekannten Voraussetzungen für den Compiler beim Generieren von Code beschränkt. Wenn ein Compiler zum Beispiel die folgende Funktion kompiliert, kennt er weder die Form (Eigenschaften-Layout) der beteiligten Objekte noch deren Eigenschaftstypen.

function compute(v, w) {

return v.x + w.y;

}

In IE9 wurde Code vom Chakra-Compiler generiert, der jede Eigenschaft zur Laufzeit lokalisierte und alle plausiblen Operationen ausführte (im obenstehenden Beispiel: Addition von ganzen Zahlen, Gleitkomma-Addition oder sogar Zeichenfolgenverkettung). Einige dieser Operationen wurden direkt im Computercode ausgeführt, andere wiederum waren auf die Unterstützung von der Laufzeit von Chakra angewiesen.

In IE10 wird vom JIT-Compiler profilbasierter, typenspezifischer Computercode generiert. Mit anderen Worten, es wird Computercode generiert, der speziell auf Objekte mit bestimmter Form oder bestimmten Werte eines bestimmten Typs zugeschnitten ist. Um den richtigen Code ausgeben zu können, muss dem Compiler bekannt sein, welche Arten von Inputwerten zu erwarten sind. Da Java-Script eine dynamische Sprache ist, ist diese Information nicht im Quellcode verfügbar. Wir haben den Interpreter von Chakra so geändert, dass er diese Informationen zur Laufzeit sammelt. Diese Methode nennen wir „dynamische Profilerstellung“. Wenn eine Funktion für die JIT-Kompilation eingeplant ist, wird das vom Interpreter erfasste Laufzeitprofil vom Compiler überprüft und ein auf den zu erwartenden Input abgestimmter Code ausgegeben.

Der Interpreter sammelt Informationen über die von ihm erfassten Ausführungen. Möglicherweise jedoch führt die Ausführung des Programms zu Laufzeitwerten, die den Annahmen für den generierten optimierten Code widersprechen. Für jede getroffene Annahme wird vom Compiler eine Laufzeitüberprüfung ausgegeben. Wenn in einer späteren Ausführung ein unerwarteter Wert auftritt, schlägt die Überprüfung fehl, die Ausführung innerhalb des spezialisierten Computercodes wird abgebrochen und im Interpreter fortgesetzt. Der Grund für den Abbruch (die fehlgeschlagene Überprüfung) wird protokolliert, zusätzliche Profilinformationen werden vom Interpreter gesammelt, und die Funktion wird mit anderen Annahmen erneut kompiliert. Abbruch und erneutes Kompilieren sind zwei grundlegend neue Funktionen in IE10.

Im Endeffekt generiert der Chakra-Compiler inIE10 weniger Computeranweisungen für Ihren Code. So wird der Speicherbedarf insgesamt reduziert und die Ausführung beschleunigt. Dies wirkt sich vor allem auf Apps mit Gleitkomma-Arithmetik und Objekteigenschaftenzugriff aus, wie den oben diskutierten HTML5-Spiele und Simulationen.

Wenn Sie JavaScript-Code im objektorientierten Stil erstellen, profitiert Ihr Code auch von der Unterstützung für Funktionsinlinekonstrukten durch Chakra. Objektorientierter Code enthält häufig zahlreiche kleinere Methoden, für die der Aufwand beim Funktionsaufruf im Vergleich zur Ausführungszeit der Funktion signifikant ist. Mithilfe von Funktionsinlinekonstrukten kann Chakra diesen Aufwand reduzieren. Entscheidender ist jedoch, dass der Umfang von anderen, herkömmlichen Compiler-Optimierungen deutlich erweitert wird, wie beispielsweise Schleifen für invariante Codebewegungen oder Kopieverteilung.

Schnellere Gleitkomma-Arithmetik

Die meisten JavaScript-Programme führen bis zu einem gewissen Grad Arithmetik für ganze Zahlen aus. Aus dem folgenden Beispiel wird ersichtlich, dass ganzzahlige Werte häufig als Iterationsvariablen in Schleifen oder als Indizes in Arrays sogar in Programmen verwendet werden, bei denen Arithmetik nicht die Hauptrolle spielt.

function findString(s, a) {

for (var i = 0, al = a.length; i < al; i++) {

if (a[i] == s) return i;

}

return -1;

}

Auf der anderen Seite ist Gleitkomma-Mathematik üblicherweise auf bestimmte Anwendungsklassen begrenzt, wie beispielsweise Spiele, Simulationen, Sound-, Bild- oder Videoprozesse usw. Bisher wurden nur wenige Anwendungen in JavaScript geschrieben, aktuelle Verbesserungen der Browserleistung haben JavaScript-Implementierungen jedoch funktionsfähig gemacht. Wir haben in IE9 Chakra für die am häufigsten verwendeten ganzzahligen Operationen optimiert. In IE10 haben wir die Gleitkomma-Mathematik erheblich verbessert.

function compute(a, b, c, d) {

return (a + b) * (c − d);

}

Ein JavaScript-Compiler kann nicht mithilfe einer einfachen Funktion, s. oben, die Argumenttypen a, b, c und d aus dem Quellcode ermitteln. Der IE9-Compiler würde annehmen, dass die Argumente mit hoher Wahrscheinlichkeit ganze Zahlen sind und schnelle Computeranweisungen für ganze Zahlen erstellen. Dies hat sehr gut funktioniert, wenn die Argumente während der Ausführung tatsächlich ganze Zahlen waren. Wurden stattdessen Gleitkommazahlen verwendet, war der Code von viel langsameren Hilfsfunktionen in der Laufzeit von Chakra abhängig. Der Aufwand an Funktionsaufrufen wurde durch Boxing und Unboxing von Zwischenwerten im Heap weiter erhöht (in den meisten 32-Bit-JavaScript-Modulen, einschließlich Chakra, müssen einzelne Gleitkommawerte dem Heap zugeordnet werden). In der oben stehenden Funktion ist für jedes Vorgangsergebnis eine Heap-Zuweisung erforderlich, danach wird der Wert auf dem Heap gespeichert und für den nächsten Vorgang aus dem Heap abgerufen.

In IE10 nutzt der Compiler die vom Interpreter gesammelten Profilinformationen, sodass erheblich schnellerer Gleitkommacode erstellt werden kann. Wenn das Profil im oben aufgeführten Beispiel anzeigt, dass alle Argumente mit hoher Wahrscheinlichkeit Gleitkommazahlen sind, gibt der Compiler Computeranweisungen im Gleitkommazahlformat aus. Der gesamte Ausdruck wird in nur drei Computeranweisungen berechnet (vorausgesetzt, alle Argumente befinden sich bereits in Registern), alle Zwischenwerte werden in Registern gespeichert, und es ist nur eine Heap-Zuweisung erforderlich, um das endgültige Ergebnis zurückzugeben.

Für Gleitkomma-intensive Anwendungen kann so eine deutliche Leistungssteigerung erzielt werden. Experimente zeigen, dass Gleitkommavorgänge in IE10 um etwa 50 % schneller als in IE9 ausgeführt werden. Zusätzlich bedeutet weniger Speicherbelegung auch weniger automatische Speicherbereinigungen.

Schnellere Objekte und Eigenschaftenzugriffe

JavaScript-Objekte sind ein praktischer und häufig verwendeter Mechanismus, um logisch zusammenhängende Wertereihen zu gruppieren. Ob Sie JavaScript-Objekte in einer strukturierten objektorientierten Programmierung oder nur als flexibles Paket für Werte verwenden: Ihr Code profitiert deutlich von den Verbesserungen der Objektzuweisung und des Eigenschaftenzugriffs in IE10.

Wie bereits erwähnt, ist ein effizienter Eigenschaftenzugriff in JavaScript kompliziert umzusetzen, da die Objektform während der Kompilierung unbekannt ist. JavaScript-Objekte können ad hoc und ohne vordefinierte Typen oder Klassen erstellt werden. Neue Eigenschaften können Objekten spontan und in jeder Reihenfolge hinzugefügt (und sogar entfernt) werden. Wenn ein Compiler die folgende Methode kompiliert, ist ihm daher nicht bekannt, wo auf dem Vektor-Objekt sich die Werte der Eigenschaften x, y, und z befinden.

Vector.prototype.magnitude = function() {

return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);

}

Wir haben in IE9 Inlinecaches eingeführt, die den Zugriff auf Eigenschaften deutlich beschleunigen. Inlinecaches erinnern sich an Objektform und -position im Objektspeicher, in dem eine bestimmte Eigenschaft zu finden ist. Inlinecaches können nur eine Objektform speichern und funktionieren einwandfrei, wenn alle Objekte einer Funktion die gleiche Form aufweisen. Wir haben in IE10 einen sekundären Cachemechanismus hinzugefügt, um die Leistung von Code zu verbessern, der in Objekten mit unterschiedlichen Formen (polymorph) ausgeführt wird.

Bevor ein Eigenschaftenwert gelesen werden kann, muss der Compiler überprüfen, ob die Objektform mit der im Inlinecache gespeicherten Form übereinstimmt. Hierfür erstellt der Compiler in IE9 vor jedem Eigenschaftenzugriff eine Formüberprüfung zur Laufzeit. Da Programme häufig mehrere Eigenschaften des gleichen Objekts kurz hintereinander lesen oder schreiben (wie im unten aufgeführten Beispiel), erzeugen diese Überprüfungen hohen Aufwand.

function collide(b1, b2) {

var dx = b1.x - b2.x;

var dy = b1.y - b2.y;

var dvx = b1.vx - b2.vx;

var dvy = b1.vy - b2.vy;

var distanceSquare = (dx * dx + dy * dy) || 1.0;

//...

}

In IE10 erstellt Chakra Code, der der erwarteten Objektform angepasst ist. Durch eine Kombination von sorgfältiger Symbolverfolgung und Abbruch und Rekompilierungsfunktionen reduziert der neuer Compiler die Zahl der durchgeführten Formüberprüfungen zur Laufzeit erheblich. Im obenstehenden Beispiel werden anstelle von acht separaten Formüberprüfungen nur zwei ausgeführt, jeweils eine für b1 und b2. Ist die Form eines Objekts erst einmal eingerichtet, sind zudem alle Eigenschaftenorte bekannt, sodass Lese- und Schreibvorgänge genauso effizient wie in C++ ausgeführt werden können.

In ECMAScript 5 können Objekte eine neue Art von Eigenschaften enthalten, die Accessor-Eigenschaften heißen. Accessor-Eigenschaften unterscheiden sich von herkömmlichen Dateneigenschaften darin, dass individuelle Abruf- und Festlegefunktionen aufgerufen werden, um Lese- und Schreibvorgänge zu behandeln. Accessor-Eigenschaften eignen sich gut für das Hinzufügen von Datenkapselung, berechneten Eigenschaften, Datenüberprüfung und Änderungsbenachrichtigungen. Das interne Typensystem und die Inlinecaches von Chakra wurden entwickelt, um Accessor-Eigenschaften und das effiziente Lesen und Schreiben ihrer Werte zu unterstützen.

Beim Schreiben von HTML5-Spielen oder -Animationen benötigt man häufig ein Physikmodul, das die nötigen Berechnungen für realistische Bewegungen von der Schwerkraft unterworfenen Objekten, die Simulation von Kollisionen usw. durchführt. Für sehr einfache Physik kann man selbst ein Modul erstellen, bei komplexeren Anforderungen empfiehlt es sich jedoch, eine der verbreiteten Physikbibliotheken zu verwenden, die inzwischen in JavaScript zur Verfügung stehen, wie etwa Box2d.js (portiert aus Box2d). Diese Bibliotheken verwenden häufig kleine Objekte wie Punkt, Vektor oder Farbe. Für jeden Animationsframe wird eine große Anzahl dieser Objekte erzeugt und sofort wieder entfernt. Deshalb ist es wichtig, dass die JavaScript-Laufzeit Objekte effizient erzeugt.

var Vector = function(x, y, z) {

this.x = x;

this.y = y;

this.z = z;

}

 

Vector.prototype = {

//...

normalize : function() {

var m = Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z));

return new Vector(this.x / m, this.y / m, this.z / m);

},

 

add : function(v, w) {

return new Vector(w.x + v.x, w.y + v.y, w.z + v.z);

},

 

cross : function(v, w) {

return new Vector(-v.z * w.y + v.y * w.z, v.z * w.x - v.x * w.z, -v.y * w.x + v.x * w.y);

},

//...

}

In IE10 wurde das interne Layout von JavaScript-Objekten optimiert, um die Objekterzeugung zu rationalisieren. In IE9 bestand jedes Objekt aus einem Header mit fester Größe und einem erweiterbaren Eigenschaften-Array. Das letztere ist erforderlich für die Unterstützung zusätzlicher Eigenschaften, die noch hinzugefügt werden können, nachdem das Objekt bereits erzeugt wurde. Nicht alle JavaScript-Anwendungen nutzen diese Flexibilität aus, und häufig erhalten Objekte die meisten ihrer Eigenschaften schon bei der Erstellung. Diese Eigenschaft ermöglicht Chakra, die meisten Eigenschaften für diese Objekte sofort anhand des Headers zuzuordnen, sodass nur eine Zuweisung (statt zwei) von Speicherplatz für jedes neu erzeugte Objekt erfolgt. Diese Änderung reduziert zudem die Zahl der Arbeitsspeicher-Dereferenzierungen, die zum Lesen oder Schreiben der Objekteigenschaft benötigt werden, und verbessert die Registerverwendung. Durch das verbesserte Objekt-Layout und die geringere Anzahl an Formüberprüfungen zur Laufzeit ergibt sich ein um bis zu 50 % schnellerer Eigenschaftenzugriff.

Verbesserungen der automatischen Speicherbereinigung

Wie oben erläutert, erstellen und entfernen HTML5-Spiele und -Animationen Objekte häufig in sehr großem Umfang. JavaScript-Programme löschen entfernte Objekte nicht explizit, um freien Speicherplatz zu schaffen. Stattdessen sind sie auf den Garbage Collector des Moduls angewiesen, der regelmäßig Speicherplatz freigibt, der nicht verwendeten Objekten zugeordnet ist. Die automatische Speicherbereinigung vereinfacht das Programmieren, erfordert jedoch in der Regel, dass die Ausführung von JavaScript von Zeit zu Zeit angehalten wird, sodass die Speicherbereinigung ausgeführt werden kann. Wenn die Speicherbereinigung viel Zeit für die Ausführung benötigt, kann es vorkommen, dass der gesamte Browser nicht mehr reagiert. In HTML5-Spielen sind selbst kurze Pausen (von Zehntel Millisekunden) störend, da sie für die Nutzer als Verzögerungen der Animation wahrnehmbar sind.

In IE10 haben wir verschiedene Verbesserungen am Speicherallocator und am Garbage Collector vorgenommen. Wir haben bereits Änderungen am Objekt-Layout und an der Erzeugung von Computercode für Gleitkomma-Arithmetik besprochen, die die Speicherbelegungsvorgänge reduzieren. Außerdem ordnet Chakra Endknotenobjekte (z. B. Zahlen und Zeichenfolgen) jetzt aus einem getrennten Speicherbereich zu. Endknotenobjekte beinhalten keine Zeiger auf andere Objekte, sodass sie während der automatischen Speicherbereinigung weniger Aufmerksamkeit erfordern als normale Objekte. Das Zuordnen von Endknotenobjekten von einem getrennten Bereich hat zwei Vorteile. Erstens kann dieser gesamte Bereich während der ersten Markierungsphase übersprungen werden, sodass diese verkürzt wird. Zweitens müssen für neue Zuordnungen aus dem Bereich des Endknotenobjekts während der gleichzeitigen Erfassung die betroffenen Seiten nicht erneut gescannt werden. Da der Collector von Chakra gleichzeitig mit dem Hauptskriptthread arbeitet, kann das ausgeführte Skript neue Objekte auf Seiten ändern oder erzeugen, die bereits verarbeitet wurden. Um sicherzustellen, dass diese Objekte nicht vorzeitig gesammelt werden, aktiviert Chakra vor Beginn der Markierungsphase den Schreibschutz für die Seiten. Seiten, auf denen während der Markierungsphase geschriebene wurde, müssen später im Hauptskriptthread erneut gescannt werden. Da für Endknotenobjekte eine solche Verarbeitung nicht erforderlich ist, müssen Seiten aus dem Bereich der Endknotenobjekte weder schreibgeschützt sein noch später erneut gescannt werden. So benötigt der Hauptskriptthread weniger Zeit, und Pausen werden reduziert. HTML5-Spiele und -Animationen profitieren deutlich von dieser Änderung, da hier häufig Gleitkommazahlen verwendet und einem Großteil des zugewiesenen Speichers heap-geschachtelte Zahlen zugewiesen werden.

Wenn der Benutzer direkt mit einer Webanwendung interagiert, ist es entscheidend, dass der Anwendungscode so schnell wie möglich ausgeführt wird – idealerweise ohne Unterbrechungen für die Speicherbereinigung. Wenn der Benutzer jedoch vom Browser zu einem anderen Programm oder auf eine andere Registerkarte wechselt, muss der Speicherbedarf der nun inaktiven Website oder Webanwendung reduziert werden. Aus diesem Grund löst Chakra in IE9 eine Sammlung für vorhandenen JavaScript-Code aus, wenn genug Speicher zugewiesen wurde. Dies funktioniert bei den meisten Anwendungen gut, ist jedoch problematisch bei mit Hochfrequenz-Timern betriebenen Anwendungen, wie z. B. HTML5-Spiele oder -Animationen. Die Sammlungen wurden bei solchen Anwendungen zu häufig ausgeführt und führten zu gelöschten Frames und einer insgesamt schlechteren Benutzererfahrung. Im Spiel Tankworld zeigte sich dieses Problem vielleicht am deutlichsten, doch auch in anderen HTML5-Simulationen wurden durch häufige Speicherbereinigungen Pausen in Animationen verursacht.

Wir haben dieses Problem in IE10 behoben, indem wir die Speicherbereinigungen mit den übrigen Funktionen des Browsers koordiniert haben. Chakra verzögert nun die Speicherbereinigung am Ende der Skriptausführung und fordert einen Rückruf vom Browser nach einem Intervall der Skriptinaktivität an. Wenn das Intervall abläuft, bevor ein Skript ausgeführt wird, beginnt Chakra eine Sammlung. Andernfalls wird die Sammlung weiter aufgeschoben. Durch diese Methode kann der Speicherbedarf verringert werden, wenn der Browser (oder eine Registerkarte des Browsers) inaktiv wird, während gleichzeitig die Häufigkeit der Sammlungen in animationsintensiven Anwendungen reduziert wird.

Diese Änderungen verringern gemeinsam den Zeitaufwand der Speicherbereinigung im Hauptskriptthread im Durchschnitt um das Vierfache für gemessene HTML5-Simulationen. Als Bestandteil der JavaScript-Ausführungszeit verringerte sich die Speicherbereinigung von 27 % auf etwa 6 %.

Zusammenfassung

IE10 erzielt eine deutliche Leistungssteigerung für JavaScript-intensive Anwendungen, insbesondere für HTML5-Spiele und -Simulationen. Diese Leistungssteigerung wurde durch einige bedeutende Verbesserungen in Chakra erreicht: von neuen, grundlegenden Funktionen des JIT-Compilers bis hin zu Änderungen am Garbage Collector.

Zusammenfassend ist die Entwicklung von IE10 ein Fortschritt, den wir feiern können. Wir sind uns jedoch auch bewusst, dass Leistungsverbesserungen eine stetige Aufgabe sind. Fast täglich testen neue Anwendungen die Grenzen moderner Browser und deren JavaScript-Module. Ohne Zweifel gibt es auch bei der nächsten Veröffentlichung genug zu tun!

Wir würden uns über Ihr Feedback als JavaScript-Entwickler zu diesem Thema freuen! Wenn Sie mit den neuen Funktionen und der verbesserten Leistung in IE10 vollkommen neue Anwendungen für Benutzer erstellen oder vorhandene verbessern konnten, teilen Sie uns das mit. Wenn Sie in IE Leistungsbeschränkungen festgestellt haben, können Sie uns natürlich ebenfalls benachrichtigen. Wir lesen alle Blog-Kommentare sorgfältig, denn wir möchten, dass IE10 und Windows 8 die umfassendste und leistungsstärkste Anwendungsplattform wird.

– Andrew Miadowicz, Programmmanager, JavaScript