{"id":42381,"date":"2024-12-03T17:05:51","date_gmt":"2024-12-03T16:05:51","guid":{"rendered":"https:\/\/www.happycoders.eu\/?p=42381"},"modified":"2026-06-10T12:21:53","modified_gmt":"2026-06-10T10:21:53","slug":"ahead-of-time-class-loading-and-linking","status":"publish","type":"post","link":"https:\/\/www.happycoders.eu\/de\/java\/ahead-of-time-class-loading-and-linking\/","title":{"rendered":"Ahead-of-Time Class Loading &amp; Linking \u2013 Turbo f\u00fcr Java-Programme"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">In diesem Artikel erf\u00e4hrst du:<\/p>\n\n\n\n<ul class=\"wp-block-list hc-checked-list\">\n<li>Warum brauchen gro\u00dfe Java-Anwendungen mehrere Sekunden, um zu starten?<\/li>\n\n\n\n<li>Was ist <em>Ahead-of-Time Class Loading &amp; Linking<\/em>, und wie kann es die Startzeit verbessern?<\/li>\n\n\n\n<li>Schritt f\u00fcr Schritt: Wie kann man durch <em>Ahead-of-Time Class Loading &amp; Linking<\/em> den Start einer Anwendung beschleunigen?<\/li>\n\n\n\n<li>Wie unterscheidet sich <em>AOT Class Loading &amp; Linking<\/em> von <em>(App)CDS<\/em>?<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"warum-starten-java-anwendungen-so-langsam\">Warum starten Java-Anwendungen so langsam?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Java-Anwendungen sind zur Laufzeit extrem flexibel. Klassen k\u00f6nnen dynamisch geladen und entladen werden. Dynamische Kompilierung, Optimierung und Deoptimierung machen Java-Programme so schnell wie C-Code \u2013 oder schneller. Und durch Reflection sind Frameworks wie Jakarta EE, Spring Boot, Quarkus, Helidon oder Micronaut \u00fcberhaupt erst m\u00f6glich.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Doch diese Vorteile haben ihren Preis:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Beim Start einer Anwendung m\u00fcssen Hunderte <code>.jar<\/code>-Dateien entpackt und Tausende <code>.class<\/code>-Dateien in den Speicher geladen, analysiert und verkn\u00fcpft werden. Der statische Initialisierungscode von Klassen muss ausgef\u00fchrt werden, und Frameworks wie Jakarta EE und Spring m\u00fcssen den Code nach Annotationen scannen, Beans instanziieren und Konfigurationscode ausf\u00fchren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Gro\u00dfe Backend-Anwendungen k\u00f6nnen so mehrere Sekunden oder sogar Minuten ben\u00f6tigen, bis sie vollst\u00e4ndig gestartet sind.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"wie-kann-der-start-von-anwendungen-beschleunigt-werden\">Wie kann der Start von Anwendungen beschleunigt werden?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Viele der im vorherigen Abschnitt beschriebenen Initialisierungsarbeiten sind bei jedem Anwendungsstart dieselben.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Im Rahmen von <a href=\"https:\/\/openjdk.org\/projects\/leyden\/\" target=\"_blank\" rel=\"noopener\">Project Leyden<\/a> wird daher daran gearbeitet, m\u00f6glichst viele dieser sich immer wiederholenden Aufgaben bereits <em>vor<\/em> dem Start einer Anwendung auszuf\u00fchren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durch <a href=\"https:\/\/openjdk.org\/jeps\/483\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 483<\/a> wurden in <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-24-features\/#Ahead-of-Time_Class_Loading_Linking_JEP_483\">Java 24 <\/a>die ersten Fr\u00fcchte dieser Arbeit ver\u00f6ffentlicht: Klassen k\u00f6nnen nun nach dem Lesen, Parsen, Laden und Linken in einer Bin\u00e4rdatei \u2013 dem <em>AOT-Cache<\/em> \u2013 gespeichert werden und sind damit bei zuk\u00fcnftigen Starts derselben Anwendung deutlich schneller in geladenem und gelinktem Zustand verf\u00fcgbar. Die JDK-Entwickler:innen haben Startzeit-Reduzierungen um bis zu 42 % gemessen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durch <a href=\"https:\/\/openjdk.org\/jeps\/514\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 514<\/a>, <em>Ahead-of-Time Command-Line Ergonomics<\/em>, wurde in <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-25-features\/#ahead-of-time-command-line-ergonomics-jep-514\">Java 25<\/a> die Generierung des AOT-Caches vereinfacht \u2013 statt zwei Schritten muss nur noch einer ausgef\u00fchrt werden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durch <a href=\"https:\/\/openjdk.org\/jeps\/514\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 515<\/a>, <em>Ahead-of-Time Method Profiling<\/em>, wurde \u2013 ebenfalls in Java 25 \u2013 der AOT-Cache um Statistiken \u00fcber Methodenaufrufe erweitert, so dass die JVM die am h\u00e4ufigsten aufgerufenen Methoden (\u201eHotspots\u201c) schon kurz nach dem Start kompilieren kann, statt erst zur Laufzeit Profildaten sammeln zu m\u00fcssen. Dadurch erreicht die Anwendung ihre Spitzenleistung schneller \u2013 gemessen wurde eine Reduzierung der Aufw\u00e4rmzeit (Warmup) um 19 %.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Und in <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-26-features\/#ahead-of-time-object-caching-with-any-gc-jep-516\">Java 26<\/a> kam mit <a href=\"https:\/\/openjdk.org\/jeps\/516\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 516<\/a>, <em>Ahead-of-Time Object Caching with Any GC<\/em>, ein weiterer Baustein hinzu: Bis dahin wurden die vorinitialisierten Objekte des AOT-Caches in einem GC-spezifischen Format direkt in den Speicher gemappt \u2013 das funktionierte nicht mit jedem Garbage Collector. Seit Java 26 k\u00f6nnen die Objekte stattdessen in einem GC-neutralen Format sequenziell geladen werden. Dadurch l\u00e4sst sich der AOT-Cache nun mit jedem Garbage Collector nutzen \u2013 einschlie\u00dflich des Low-Latency-Collectors ZGC, der bisher au\u00dfen vor war.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"wie-funktioniert-ahead-of-time-class-loading-linking\">Wie funktioniert Ahead-of-Time Class Loading &amp; Linking?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Um den Programmstart durch AOT Class Loading &amp; Linking zu beschleunigen, m\u00fcssen wir drei Schritte (bzw. zwei, dazu unten mehr) durchf\u00fchren:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>In einem ersten Schritt wird die Anwendung in einem sogenannten Trainingslauf gestartet. Dabei analysiert die JVM alle geladenen und gelinkten Klassen und erzeugt eine Konfigurationsdatei mit den relevanten Informationen \u00fcber diese Klassen \u2013 und ab Java 25 zus\u00e4tzlich \u00fcber Methoden-Aufrufstatistiken.<\/li>\n\n\n\n<li>In einem zweiten Schritt wird mit Hilfe dieser Konfigurationsdatei die bin\u00e4re Cache-Datei erzeugt.<\/li>\n\n\n\n<li>Bei jedem weiteren Start der Anwendung wird diese Cache-Datei mit angegeben, und die Anwendung l\u00e4dt die Klassen in geladener und gelinkter Form direkt aus diesem Cache \u2013 und ab Java 25 beginnt sie direkt mit der Optimierung der am h\u00e4ufigsten aufgerufenen Methoden (\u201eHotspots\u201c).<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Das h\u00f6rt sich komplizierter an als es ist. Im Folgenden f\u00fchre ich dich Schritt f\u00fcr Schritt anhand einer Beispielanwendung durch diese Schritte bis hin zum beschleunigten Start der Anwendung.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"noch-einmal-schritt-fuer-schritt-zum-mitmachen\">Noch einmal Schritt f\u00fcr Schritt zum Mitmachen<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Ich zeige dir in diesem Abschnitt an einer kleinen Anwendung Schritt f\u00fcr Schritt, wie Ahead-of-Time Class Loading &amp; Linking funktioniert.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wir benutzen dazu ein ganz einfaches Demo-Programm, das lediglich die aktuelle Zeit anzeigt.<\/p>\n\n\n\n<div class=\"wp-block-uagb-container uagb-block-8ae4ca2e alignfull uagb-is-root-container\">\n<div class=\"uagb-block-b769b372 uagb-infobox__content-wrap  uagb-infobox-icon-left uagb-infobox-left uagb-infobox-stacked-mobile uagb-infobox-image-valign-top \"><div class=\"uagb-ifb-icon-wrap\"><svg xmlns=\"https:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\"><path d=\"M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z\"><\/path><\/svg><\/div><div class=\"uagb-ifb-content\"><div class=\"uagb-ifb-title-wrap\"><\/div><p class=\"uagb-ifb-desc\">Wir verwenden hier eine <a href=\"https:\/\/www.happycoders.eu\/de\/java\/main-methode\/#compact-source-files-and-instance-main-methods\">kompakte Quelldatei (Compact Source File)<\/a> <a href=\"https:\/\/www.happycoders.eu\/de\/java\/main-methode\/#compact-source-files-and-instance-main-methods\">mit einer Instanz-Main-Methode<\/a>. Dadurch m\u00fcssen wir keine Klasse definieren und k\u00f6nnen statt <code>public static void main(String[] args)<\/code> einfach <code>void main()<\/code> schreiben.<\/p><\/div><\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Lade dir ein aktuelles JDK herunter \u2013 idealerweise <a href=\"https:\/\/jdk.java.net\/25\/\" target=\"_blank\" rel=\"noopener\">Java 25 (LTS)<\/a> oder <a href=\"https:\/\/jdk.java.net\/26\/\" target=\"_blank\" rel=\"noopener\">Java 26<\/a>. Ahead-of-Time Class Loading &amp; Linking ist seit Java 24 verf\u00fcgbar; die in diesem Beispiel genutzten kompakten Quelldateien mit Instanz-Main-Methode sind seit Java 25 final, und die Option <code>-XX:AOTCacheOutput<\/code>, mit der wir die ersten beiden Schritte zu einem kombinieren k\u00f6nnen, steht ebenfalls ab Java 25 zur Verf\u00fcgung.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Speichere den folgenden Quellcode in der Datei <code>AotTest.java<\/code> ab:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n    <span class=\"hljs-keyword\">var<\/span> now = LocalDateTime.now();\n    <span class=\"hljs-keyword\">var<\/span> nowString = now.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM));\n    System.out.println(<span class=\"hljs-string\">\"Hello, it's \"<\/span> + nowString);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Kompiliere den Code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">javac AotTest.java<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Erzeuge eine JAR-Datei:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">jar cvf AotTest.jar AotTest.class<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Starte dann den Trainingslauf mit folgendem Aufruf:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">java -XX:AOTMode=record -XX:AOTConfiguration=AotTest.conf \\\n    -cp AotTest.jar AotTest<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Dadurch wird die Konfigurationsdatei <code>AotTest.conf<\/code> erzeugt. Diese kannst du mit einem Texteditor \u00f6ffnen \u2013 sie enth\u00e4lt eine lange Liste von Klassen und Daten zu diesen Klassen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Danach erzeugst du mit folgendem Aufruf den Klassen-Cache in der Datei <code>AotTest.aot<\/code> (die Anwendung wird hierbei nicht noch einmal ausgef\u00fchrt):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">java -XX:AOTMode=create -XX:AOTConfiguration=AotTest.conf -XX:AOTCache=AotTest.aot \\\n    -cp AotTest.jar<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-uagb-container uagb-block-6731c60d alignfull uagb-is-root-container\">\n<div class=\"uagb-block-7bac1066 uagb-infobox__content-wrap  uagb-infobox-icon-left uagb-infobox-left uagb-infobox-stacked-mobile uagb-infobox-image-valign-top \"><div class=\"uagb-ifb-icon-wrap\"><svg xmlns=\"https:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\"><path d=\"M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z\"><\/path><\/svg><\/div><div class=\"uagb-ifb-content\"><div class=\"uagb-ifb-title-wrap\"><\/div><p class=\"uagb-ifb-desc\"><strong>Seit Java 25<\/strong> kannst du Trainingslauf und Erzeugung des Caches (die beiden vorangegangenen Schritte) in einem kombinierten Schritt ausf\u00fchren:<br><br><code>java -XX:AOTCacheOutput=AotTest.aot -cp AotTest.jar AotTest<\/code><\/p><\/div><\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Und zuletzt startest du die Anwendung und gibst dabei die zu benutzende Cache-Datei an:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">java -XX:AOTCache=AotTest.aot -cp AotTest.jar AotTest<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-uagb-container uagb-block-3acaf388 alignfull uagb-is-root-container\">\n<div class=\"uagb-block-6bdfca52 uagb-infobox__content-wrap  uagb-infobox-icon-left uagb-infobox-left uagb-infobox-stacked-mobile uagb-infobox-image-valign-top \"><div class=\"uagb-ifb-icon-wrap\"><svg xmlns=\"https:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\"><path d=\"M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z\"><\/path><\/svg><\/div><div class=\"uagb-ifb-content\"><div class=\"uagb-ifb-title-wrap\"><\/div><p class=\"uagb-ifb-desc\"><strong>Hinweis f\u00fcr Java 24:<\/strong> <br><br>Auf Java 24 sind ein paar zus\u00e4tzliche Schritte n\u00f6tig. Die kompakten Quelldateien mit Instanz-Main-Methode hie\u00dfen dort noch \u201eSimple Source Files and Instance Main Methods\u201c (JEP 495) und befanden sich im Preview-Stadium. Du musst sie deshalb beim Kompilieren mit <code>javac --enable-preview --source 24 AotTest.java<\/code> aktivieren und bei jedem <code>java<\/code>-Aufruf <code>--enable-preview<\/code> erg\u00e4nzen.<br><br>Au\u00dferdem steht die Option <code>-XX:AOTCacheOutput<\/code> erst ab Java 25 zur Verf\u00fcgung \u2013 den kombinierten Schritt gibt es auf Java 24 also noch nicht.<\/p><\/div><\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Lass uns nun einmal die Startzeit der Anwendung mit und ohne Cache vergleichen.<\/p>\n\n\n\n<div class=\"wp-block-uagb-container uagb-block-ff1bcc01 alignfull uagb-is-root-container\">\n<div class=\"uagb-block-7e98a7ab uagb-infobox__content-wrap  uagb-infobox-icon-left uagb-infobox-left uagb-infobox-stacked-mobile uagb-infobox-image-valign-top \"><div class=\"uagb-ifb-icon-wrap\"><svg xmlns=\"https:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\"><path d=\"M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z\"><\/path><\/svg><\/div><div class=\"uagb-ifb-content\"><div class=\"uagb-ifb-title-wrap\"><\/div><p class=\"uagb-ifb-desc\">Im Folgenden verwende ich das Linux-Kommando <code>time<\/code>. Unter Windows kannst du das Tool <code>ptime<\/code> verwenden, das du \u00fcber den Package Manager <a href=\"https:\/\/chocolatey.org\/\" target=\"_blank\" rel=\"noopener\">Chocolatey<\/a> mit dem Kommando <code>choco install ptime<\/code> installieren kannst.<\/p><\/div><\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Zun\u00e4chst ein Aufruf <em>ohne<\/em> Cache:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">time java -cp AotTest.jar AotTest<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Bei f\u00fcnf Aufrufen ergab sich bei mir eine mittlere Laufzeit von 0,137 Sekunden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Und jetzt ein Aufruf <em>mit<\/em> Cache:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">time java -XX:AOTCache=AotTest.aot -cp AotTest.jar AotTest<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Hier ergab sich aus f\u00fcnf Aufrufen eine mittlere Laufzeit von 0,086 Sekunden. Das ist eine beeindruckende Leistungssteigerung von 37 %, die nah an die von den Entwickler:innen gemessenen 42 % herankommt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"und-was-ist-mit-appcds\">Und was ist mit AppCDS?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Du fragst dich jetzt vielleicht: Was ist der Unterschied zwischen <em>Ahead-of-Time Class Loading &amp; Linking<\/em> und <em>(Application) Class Data Sharing<\/em>?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-10-features\/#Class-Data_Sharing\">Class Data Sharing (CDS)<\/a> existiert bereits seit Java 5 und erm\u00f6glicht es, die Klassen des JDK in einem plattformspezifischen Bin\u00e4rformat zu speichern, aus dem die Klassen dann deutlich schneller geladen werden k\u00f6nnen als aus <code>.class<\/code>-Dateien.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In Java 10 kam dann <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-10-features\/#Application_Class-Data_Sharing_Schritt_fuer_Schritt\">Application Class Data Sharing (AppCDS)<\/a> hinzu, wodurch nicht mehr nur JDK-Klassen, sondern auch Anwendungsklassen in diesem Bin\u00e4rformat gespeichert werden k\u00f6nnen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Tats\u00e4chlich baut Ahead-of-Time Class Loading &amp; Linking auf (App)CDS auf. Falls du dir vorhin die Datei <code>AotTest.conf<\/code> angeschaut hast, ist dir vielleicht aufgefallen, dass der Header sagt, es handle sich um ein \u201eCDS archive dump\u201c.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">W\u00e4hrend Class Data Sharing die Klassen lediglich liest, parst und dann in einem Bin\u00e4rformat speichert, werden die Klassen beim AOT Class Loading &amp; Linking zus\u00e4tzlich \u2013 wie der Name schon sagt \u2013 in <code>Class<\/code>-Objekte geladen und gelinkt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die Leyden-Entwickler:innen haben beide Mechanismen mit der <a href=\"https:\/\/github.com\/spring-projects\/spring-petclinic\" target=\"_blank\" rel=\"noopener\">Spring PetClinic<\/a> getestet. Durch AppCDS wurde die Ladezeit der Anwendung um 33 % beschleunigt und durch AOT Class Loading &amp; Linking um 42 %. Falls du also bereits AppCDS einsetzt, wird die Startzeitverbesserung durch AOT Class Loading &amp; Linking nicht mehr ganz so signifikant ausfallen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"fazit\">Fazit<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Java ist eine sehr flexible und m\u00e4chtige Sprache, doch diese Flexibilit\u00e4t kann bei gr\u00f6\u00dferen Anwendungen zu Startzeiten im Bereich von mehreren Sekunden bis Minuten f\u00fchren. Beim Start werden u. a. Java-Klassen gelesen, geparst, geladen und gelinkt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durch Ahead-of-Time Class Loading &amp; Linking k\u00f6nnen diese Schritte vor dem Start der Anwendung einmalig ausgef\u00fchrt werden und dadurch der eigentliche Start der Anwendung \u2013 nach Aussage der Entwickler:innen dieses Features \u2013 um bis zu 42 % beschleunigt werden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durch Ahead-of-Time Method Profiling werden zudem Statistiken \u00fcber Methodenaufrufe im AOT-Cache gespeichert, so dass direkt nach Start der Anwendung h\u00e4ufig aufgerufene Methoden (\u201eHotspots\u201c) optimiert werden k\u00f6nnen. Und seit Java 26 funktioniert das Objekt-Caching des AOT-Caches mit jedem Garbage Collector \u2013 auch mit dem Low-Latency-Collector ZGC.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Damit ist das Ende der Entwicklung noch nicht erreicht: Als n\u00e4chster Schritt zeichnet sich in Project Leyden die <em>Ahead-of-Time-Code-Compilation<\/em> ab \u2013 das Vorkompilieren h\u00e4ufig genutzter Methoden in nativen Code, der dann ebenfalls im AOT-Cache abgelegt wird. Bisher liegt dazu allerdings erst ein <a href=\"https:\/\/openjdk.org\/jeps\/8335368\" target=\"_blank\" rel=\"noopener\">JEP draft: Ahead-of-Time Code Compilation<\/a> vor, der noch keiner Java-Version zugeordnet ist.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Falls du dieses Feature ausprobierst, schreib mir gerne deine Erfahrungen in die Kommentare \u2013 ich bin gespannt auf deine Messwerte und deine Meinung!<\/p>\n<aside><p>Wenn dir der Artikel weitergeholfen hat, w\u00fcrde ich mich sehr \u00fcber eine positive Bewertung auf meinem <a href=\"https:\/\/www.provenexpert.com\/de-de\/sven-woltmann-happycoders-eu\/7smk\/\" target=\"_blank\" rel=\"noopener\">ProvenExpert-Profil<\/a> freuen. Dein Feedback hilft mir, meine Inhalte weiter zu verbessern und motiviert mich, neue informative Artikel zu schreiben.<\/p>\r\n                        <p>\ud83d\udc49 <a href=\"https:\/\/www.provenexpert.com\/de-de\/sven-woltmann-happycoders-eu\/7smk\/\" target=\"_blank\" rel=\"noopener\">Bewertung abgeben<\/a><\/p>\r\n                        <p>Du m\u00f6chtest \u00fcber alle neuen Java-Features auf dem Laufenden sein? Dann <a href=\"#\" data-formkit-toggle=\"d8ee997126\">klicke hier<\/a>, um dich f\u00fcr den HappyCoders-Newsletter anzumelden.<\/p>\r\n                        <p>\ud83d\udc49 <a href=\"#\" data-formkit-toggle=\"d8ee997126\">Newsletter-Anmeldung<\/a><\/p><\/aside>","protected":false},"excerpt":{"rendered":"<p>Was ist Ahead-of-Time Class Loading &#038; Linking? Wie funktioniert es, und wie kann es die Startzeit von Java-Programmen um 42 % verbessern? Wie unterscheidet es sich von Application Class Data Loading (AppCDS)?<\/p>\n","protected":false},"author":1,"featured_media":42383,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_seopress_titles_title":"Ahead-of-Time Class Loading & Linking \u2013 Turbo f\u00fcr Java","_seopress_titles_desc":"Ahead-of-Time Class Loading & Linking beschleunigt den Start von Java-Anwendungen um bis zu 42 %. So erstellst du den AOT-Cache \u2013 kurz erkl\u00e4rt.","_seopress_robots_index":"","_seopress_robots_follow":"","_seopress_robots_imageindex":"","_seopress_robots_snippet":"","_seopress_robots_primary_cat":"","_seopress_robots_breadcrumbs":"","_seopress_robots_freeze_modified_date":"","_seopress_robots_custom_modified_date":"","_seopress_robots_canonical":"","_seopress_social_fb_title":"","_seopress_social_fb_desc":"","_seopress_social_fb_img":"","_seopress_social_fb_img_attachment_id":0,"_seopress_social_fb_img_width":0,"_seopress_social_fb_img_height":0,"_seopress_social_twitter_title":"","_seopress_social_twitter_desc":"","_seopress_social_twitter_img":"","_seopress_social_twitter_img_attachment_id":0,"_seopress_social_twitter_img_width":0,"_seopress_social_twitter_img_height":0,"_seopress_redirections_value":"","_seopress_redirections_enabled":"","_seopress_redirections_enabled_regex":"","_seopress_redirections_logged_status":"","_seopress_redirections_param":"","_seopress_redirections_type":0,"_seopress_analysis_target_kw":"Ahead-of-Time Class Loading & Linking","_seopress_news_disabled":"","_seopress_video_disabled":"","_seopress_video":[],"_seopress_pro_schemas_manual":[],"_seopress_pro_rich_snippets_disable_all":"","_seopress_pro_rich_snippets_disable":[],"_seopress_pro_schemas":[],"_uag_custom_page_level_css":"","_wp_convertkit_post_meta":{"form":"-1","landing_page":"","tag":"0","restrict_content":"0"},"_metis_text_type":"standard","_metis_text_length":10836,"_post_count":0,"footnotes":""},"categories":[64],"tags":[165],"class_list":["post-42381","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-java","tag-java-fortgeschritten"],"uagb_featured_image_src":{"full":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking.jpg",1770,986,false],"thumbnail":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking.jpg",150,84,false],"medium":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking.jpg",300,167,false],"medium_large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking.jpg",768,428,false],"large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking.jpg",1024,570,false],"feature_thumb_224":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking-224x125.jpg",224,125,true],"feature_thumb_336":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking-336x187.jpg",336,187,true],"feature_thumb_504":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking-504x281.jpg",504,281,true],"feature_thumb_672":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking-672x374.jpg",672,374,true],"half_400":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking-400x223.jpg",400,223,true],"half_600":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking-600x334.jpg",600,334,true],"full_800":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking-800x446.jpg",800,446,true],"full_944":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking-944x526.jpg",944,526,true],"full_1200":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking-1200x668.jpg",1200,668,true],"wide_1180":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking-1180x490.jpg",1180,490,true],"wide_1770":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking-1770x735.jpg",1770,735,true],"1536x1536":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking.jpg",1536,856,false],"2048x2048":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/ahead-of-time-class-loading-linking.jpg",1770,986,false]},"uagb_author_info":{"display_name":"Sven Woltmann","author_link":"https:\/\/www.happycoders.eu\/de\/author\/sven\/"},"uagb_comment_info":0,"uagb_excerpt":"Was ist Ahead-of-Time Class Loading & Linking? Wie funktioniert es, und wie kann es die Startzeit von Java-Programmen um 42 % verbessern? Wie unterscheidet es sich von Application Class Data Loading (AppCDS)?","public_identification_id":"145e9036639048a4abff9a72ab8460df","private_identification_id":"dee7187496404937b2154119d72236a7","_links":{"self":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/42381","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/comments?post=42381"}],"version-history":[{"count":30,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/42381\/revisions"}],"predecessor-version":[{"id":56692,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/42381\/revisions\/56692"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media\/42383"}],"wp:attachment":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media?parent=42381"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/categories?post=42381"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/tags?post=42381"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}