Java-Leistung - Java performance

In der Softwareentwicklung galt die Programmiersprache Java historisch als langsamer als die schnellsten typisierten Sprachen der 3. Generation wie C und C ++ . Der Hauptgrund ist ein anderes Sprachdesign, bei dem Java-Programme nach dem Kompilieren auf einer virtuellen Java-Maschine (JVM) ausgeführt werden und nicht wie C- und C ++ - Programme als nativer Code direkt auf dem Prozessor des Computers . Die Leistung gab Anlass zur Sorge, da viel Unternehmenssoftware in Java geschrieben wurde, nachdem die Sprache Ende der 1990er und Anfang der 2000er Jahre schnell populär wurde.

Seit Ende der neunziger Jahre hat sich die Ausführungsgeschwindigkeit von Java-Programmen durch die Einführung der Just-in-Time-Kompilierung (JIT) (1997 für Java 1.1 ), die Hinzufügung von Sprachfunktionen zur Unterstützung einer besseren Codeanalyse und Optimierungen in der JVM (z als HotSpot , der im Jahr 2000 zum Standard für Suns JVM wurde). Die Hardwareausführung von Java-Bytecode, wie er beispielsweise von ARMs Jazelle angeboten wird , wurde ebenfalls untersucht, um signifikante Leistungsverbesserungen zu erzielen.

Die Leistung eines Java-Bytecode- kompilierten Java-Programms hängt davon ab, wie optimal die angegebenen Aufgaben von der virtuellen Java-Hostmaschine (JVM) verwaltet werden und wie gut die JVM dabei die Funktionen der Computerhardware und des Betriebssystems (OS) ausnutzt . Daher muss bei jedem Java-Leistungstest oder -Vergleich immer die Version, der Hersteller, das Betriebssystem und die Hardwarearchitektur der verwendeten JVM angegeben werden. In ähnlicher Weise hängt die Leistung des entsprechenden nativ kompilierten Programms von der Qualität des generierten Maschinencodes ab. Daher muss der Test oder Vergleich auch den Namen, die Version und den Hersteller des verwendeten Compilers sowie die aktivierten Anweisungen zur Compileroptimierung angeben .

Optimierungsmethoden für virtuelle Maschinen

Viele Optimierungen haben die Leistung der JVM im Laufe der Zeit verbessert. Obwohl Java häufig die erste virtuelle Maschine war , die sie erfolgreich implementierte, wurden sie häufig auch auf anderen ähnlichen Plattformen verwendet.

Just-in-Time-Kompilierung

Frühe JVMs interpretierten immer Java-Bytecodes . Dies hatte einen großen Leistungsverlust zwischen einem Faktor 10 und 20 für Java gegenüber C in durchschnittlichen Anwendungen. Um dem entgegenzuwirken, wurde in Java 1.1 ein Just-in-Time-Compiler (JIT) eingeführt. Aufgrund der hohen Kompilierungskosten wurde in Java 1.2 ein zusätzliches System namens HotSpot eingeführt, das in Java 1.3 als Standard festgelegt wurde. Mit diesem Framework analysiert die Java Virtual Machine kontinuierlich die Programmleistung auf Hotspots, die häufig oder wiederholt ausgeführt werden. Diese sollen dann optimiert werden , was zu einer Hochleistungsausführung mit minimalem Overhead für weniger leistungskritischen Code führt. Einige Benchmarks zeigen auf diese Weise einen 10-fachen Geschwindigkeitsgewinn. Aus zeitlichen Gründen kann der Compiler das Programm jedoch nicht vollständig optimieren, sodass das resultierende Programm langsamer ist als native Codealternativen.

Adaptive Optimierung

Die adaptive Optimierung ist eine Methode in der Informatik, die eine dynamische Neukompilierung von Teilen eines Programms basierend auf dem aktuellen Ausführungsprofil durchführt. Mit einer einfachen Implementierung kann ein adaptiver Optimierer einfach einen Kompromiss zwischen Just-in-Time-Kompilierungs- und Interpretationsanweisungen eingehen. Auf einer anderen Ebene kann die adaptive Optimierung lokale Datenbedingungen ausnutzen, um Verzweigungen zu optimieren und die Inline-Erweiterung zu verwenden.

Eine virtuelle Java-Maschine wie HotSpot kann auch Code, der früher JITed war, auch deoptimieren . Dies ermöglicht aggressive (und möglicherweise unsichere) Optimierungen, während der Code später noch deoptimiert und auf einen sicheren Pfad zurückgegriffen werden kann.

Müllabfuhr

Die Java Virtual Machines (JVMs) 1.0 und 1.1 verwendeten einen Mark-Sweep-Collector , der den Heap nach einer Garbage Collection fragmentieren konnte . Ab Java 1.2 wurden die JVMs zu einem Generationskollektor , der ein viel besseres Defragmentierungsverhalten aufweist. Moderne JVMs verwendet eine Vielzahl von Methoden , die weiter verbessert haben Garbage Collection Leistung.

Andere Optimierungsmethoden

Komprimierte Ups

Mit Compressed Oops kann Java 5.0+ bis zu 32 GB Heap mit 32-Bit-Referenzen adressieren. Java unterstützt nicht den Zugriff auf einzelne Bytes, sondern nur auf Objekte, die standardmäßig auf 8 Bytes ausgerichtet sind. Aus diesem Grund sind die niedrigsten 3 Bits einer Heap-Referenz immer 0. Durch Verringern der Auflösung von 32-Bit-Referenzen auf 8-Byte-Blöcke kann der adressierbare Speicherplatz auf 32 GB erhöht werden. Dies reduziert die Speichernutzung im Vergleich zur Verwendung von 64-Bit-Referenzen erheblich, da Java Referenzen viel häufiger verwendet als einige Sprachen wie C ++. Java 8 unterstützt größere Ausrichtungen wie die 16-Byte-Ausrichtung, um bis zu 64 GB mit 32-Bit-Referenzen zu unterstützen.

Geteilte Bytecode-Überprüfung

Vor dem Ausführen einer Klasse überprüft die Sun JVM ihre Java-Bytecodes (siehe Bytecode-Überprüfung ). Diese Überprüfung wird träge durchgeführt: Die Bytecodes der Klassen werden nur geladen und überprüft, wenn die bestimmte Klasse geladen und für die Verwendung vorbereitet ist, und nicht zu Beginn des Programms. Da es sich bei den Java- Klassenbibliotheken jedoch auch um reguläre Java-Klassen handelt, müssen sie bei ihrer Verwendung ebenfalls geladen werden. Dies bedeutet, dass die Startzeit eines Java-Programms häufig länger ist als beispielsweise bei C ++ - Programmen.

In der JVM wird seit Java Version 6 eine Methode namens Split-Time-Verification verwendet , die erstmals in der Java-Plattform Micro Edition (J2ME) eingeführt wurde . Die Überprüfung des Java-Bytecodes wird in zwei Phasen unterteilt:

  • Entwurfszeit - beim Kompilieren einer Klasse von der Quelle zum Bytecode
  • Laufzeit - beim Laden einer Klasse.

In der Praxis erfasst diese Methode das Wissen des Java-Compilers über den Klassenfluss und kommentiert die kompilierten Methodenbytecodes mit einer Zusammenfassung der Klassenflussinformationen. Dies macht die Laufzeitüberprüfung nicht wesentlich weniger komplex, ermöglicht jedoch einige Verknüpfungen.

Fluchtanalyse und Vergröberung der Sperren

Java ist in der Lage, Multithreading auf Sprachebene zu verwalten . Multithreading ist eine Methode, mit der Programme mehrere Prozesse gleichzeitig ausführen können, wodurch schnellere Programme auf Computersystemen mit mehreren Prozessoren oder Kernen erstellt werden. Eine Multithread-Anwendung kann auch bei langen Aufgaben auf Eingaben reagieren.

Programme, die Multithreading verwenden, müssen jedoch besonders auf Objekte achten , die von Threads gemeinsam genutzt werden, und den Zugriff auf gemeinsam genutzte Methoden oder Blöcke sperren, wenn sie von einem der Threads verwendet werden. Das Sperren eines Blocks oder Objekts ist aufgrund der Art der zugrunde liegenden Operation auf Betriebssystemebene eine zeitaufwändige Operation (siehe Parallelitätskontrolle und Sperrgranularität ).

Da die Java-Bibliothek nicht weiß, welche Methoden von mehr als einem Thread verwendet werden, sperrt die Standardbibliothek bei Bedarf in einer Multithread-Umgebung immer Blöcke .

Vor Java 6 hat die virtuelle Maschine Objekte und Blöcke immer gesperrt , wenn sie vom Programm dazu aufgefordert wurden, auch wenn kein Risiko bestand, dass ein Objekt von zwei verschiedenen Threads gleichzeitig geändert wurde. In diesem Fall vector wurde beispielsweise vor jedem der Add- Vorgänge ein Local gesperrt , um sicherzustellen, dass es nicht von anderen Threads geändert wird (der Vektor wird synchronisiert). Da dies jedoch für die Methode streng lokal ist, ist dies unnötig:

public String getNames() {
     Vector<String> v = new Vector<>();
     v.add("Me");
     v.add("You");
     v.add("Her");
     return v.toString();
}

Ab Java 6 werden Codeblöcke und Objekte nur bei Bedarf gesperrt, sodass die virtuelle Maschine im obigen Fall das Vector-Objekt überhaupt nicht sperren würde.

Seit Version 6u23 unterstützt Java die Escape-Analyse.

Verbesserungen bei der Registerzuordnung

Vor Java 6 , Zuweisung von Registern war sehr primitiv in der Client virtuellen Maschine (sie über keine lebenden tat Blöcke ), was ein Problem in war CPU - Designs , die weniger hatten Prozessor - Register zur Verfügung, wie es in x86s . Wenn für eine Operation keine Register mehr verfügbar sind, muss der Compiler von Register zu Speicher (oder von Speicher zu Register) kopieren , was einige Zeit in Anspruch nimmt (der Zugriff auf Register ist erheblich schneller). Die virtuelle Servermaschine verwendete jedoch einen Farbdiagramm- Allokator und hatte dieses Problem nicht.

Eine Optimierung der Registerzuordnung wurde in Suns JDK 6 eingeführt. Es war dann möglich, dieselben Register blockweise zu verwenden (falls zutreffend), wodurch die Zugriffe auf den Speicher reduziert wurden. Dies führte bei einigen Benchmarks zu einem gemeldeten Leistungszuwachs von etwa 60%.

Klassendatenfreigabe

Die gemeinsame Nutzung von Klassendaten (von Sun als CDS bezeichnet) ist ein Mechanismus, der die Startzeit für Java-Anwendungen und den Speicherbedarf verringert . Wenn die JRE installiert ist, lädt das Installationsprogramm eine Reihe von Klassen aus der System- JAR- Datei (die JAR-Datei mit der gesamten Java-Klassenbibliothek mit dem Namen rt.jar) in eine private interne Darstellung und speichert diese Darstellung in einer Datei mit dem Namen a "gemeinsames Archiv". Bei nachfolgenden JVM-Aufrufen wird dieses gemeinsam genutzte Archiv speicherabgebildet , wodurch die Kosten für das Laden dieser Klassen gespart werden und ein Großteil der Metadaten der JVM für diese Klassen von mehreren JVM-Prozessen gemeinsam genutzt werden kann.

Die entsprechende Verbesserung der Startzeit ist bei kleinen Programmen offensichtlicher.

Geschichte der Leistungsverbesserungen

Abgesehen von den hier aufgeführten Verbesserungen führte jede Java-Version viele Leistungsverbesserungen in der JVM- und Java- Anwendungsprogrammierschnittstelle (API) ein.

JDK 1.1.6: Erste Just-in-Time-Kompilierung ( Symantecs JIT-Compiler)

J2SE 1.2: Verwendung eines Generationskollektors .

J2SE 1.3: Just-in-Time-Kompilierung mit HotSpot .

J2SE 1.4: Hier finden Sie eine Sun-Übersicht über Leistungsverbesserungen zwischen den Versionen 1.3 und 1.4.

Java SE 5.0: Klassendatenfreigabe

Java SE 6:

Weitere Verbesserungen:

  • Verbesserungen der Java OpenGL Java 2D- Pipeline-Geschwindigkeit
  • Die Java 2D-Leistung wurde auch in Java 6 erheblich verbessert

Siehe auch 'Sun-Übersicht über Leistungsverbesserungen zwischen Java 5 und Java 6'.

Java SE 6 Update 10

  • Java Quick Starter reduziert die Startzeit der Anwendung, indem ein Teil der JRE-Daten beim Start des Betriebssystems im Festplatten-Cache vorgeladen wird .
  • Teile der Plattform, die zum Ausführen einer Anwendung erforderlich sind, auf die über das Web zugegriffen wird, wenn JRE nicht installiert ist, werden jetzt zuerst heruntergeladen. Die volle JRE beträgt 12 MB, eine typische Swing-Anwendung muss zum Starten nur 4 MB herunterladen. Die restlichen Teile werden dann im Hintergrund heruntergeladen.
  • Die Grafikleistung unter Windows wurde durch die umfassende Verwendung von Direct3D standardmäßig verbessert. Verwenden Sie Shader auf der Grafikverarbeitungseinheit (GPU), um komplexe Java 2D- Vorgänge zu beschleunigen .

Java 7

Für Java 7 wurden mehrere Leistungsverbesserungen veröffentlicht: Zukünftige Leistungsverbesserungen sind für ein Update von Java 6 oder Java 7 geplant:

  • Bereitstellung von JVM-Unterstützung für dynamische Programmiersprachen nach den Prototyping-Arbeiten, die derzeit an der Da Vinci-Maschine (Multi Language Virtual Machine) durchgeführt werden.
  • Erweitern Sie die vorhandene Parallelitätsbibliothek, indem Sie Parallel Computing auf Multi-Core- Prozessoren verwalten.
  • Ermöglichen Sie der JVM, sowohl die Client- als auch die Server- JIT-Compiler in derselben Sitzung mit einer Methode namens Tiered Compiling zu verwenden:
    • Der Client wird beim Start verwendet (da er beim Start und für kleine Anwendungen gut ist).
    • Der Server würde für die langfristige Ausführung der Anwendung verwendet (da er den Client- Compiler dafür übertrifft ).
  • Ersetzen Sie den vorhandenen gleichzeitigen Garbage Collector mit niedriger Pause (auch als CMS-Kollektor (Concurrent Mark-Sweep) bezeichnet) durch einen neuen Collector namens Garbage First (G1), um im Laufe der Zeit konsistente Pausen sicherzustellen.

Vergleich mit anderen Sprachen

Der objektive Vergleich der Leistung eines Java-Programms mit einem gleichwertigen Programm, das in einer anderen Sprache wie C ++ geschrieben wurde, erfordert einen sorgfältig und sorgfältig erstellten Benchmark, der Programme vergleicht, die identische Aufgaben ausführen. Die Zielplattform von Java - Bytecode - Compiler ist die Java - Plattform und der Bytecode entweder interpretiert oder in Maschinencode von der JVM zusammengestellt. Andere Compiler zielen fast immer auf eine bestimmte Hardware- und Softwareplattform ab und erzeugen Maschinencode, der während der Ausführung praktisch unverändert bleibt. Aus diesen beiden unterschiedlichen Ansätzen ergeben sich sehr unterschiedliche und schwer zu vergleichende Szenarien: statische und dynamische Kompilierungen und Neukompilierungen , Verfügbarkeit präziser Informationen über die Laufzeitumgebung und andere.

Java wird häufig zur Laufzeit von der virtuellen Java- Maschine just-in-time kompiliert , kann aber ebenso wie C ++ vorab kompiliert werden . Bei der Just-in-Time-Kompilierung geben die Mikro-Benchmarks von The Computer Language Benchmarks Game Folgendes über die Leistung an:

  • langsamer als kompilierte Sprachen wie C oder C ++ ,
  • ähnlich wie bei anderen Just-in-Time-kompilierten Sprachen wie C # ,
  • viel schneller als Sprachen ohne einen effektiven Native-Code-Compiler ( JIT oder AOT ) wie Perl , Ruby , PHP und Python .

Programmgeschwindigkeit

Benchmarks messen häufig die Leistung kleiner numerisch intensiver Programme. In einigen seltenen realen Programmen übertrifft Java C. Ein Beispiel ist der Benchmark von Jake2 (ein Klon von Quake II , der in Java durch Übersetzung des ursprünglichen GPL C-Codes geschrieben wurde). Die Java 5.0-Version bietet in einigen Hardwarekonfigurationen eine bessere Leistung als das C-Gegenstück. Es ist zwar nicht angegeben, wie die Daten gemessen wurden (z. B. wenn die 1997 kompilierte ursprüngliche ausführbare Quake II-Datei verwendet wurde, was als schlecht angesehen werden kann, da aktuelle C-Compiler möglicherweise bessere Optimierungen für Quake erzielen), es wird jedoch darauf hingewiesen, dass derselbe Java-Quellcode verwendet wird kann allein durch die Aktualisierung der VM einen enormen Geschwindigkeitsschub erzielen, was mit einem 100% statischen Ansatz unmöglich zu erreichen ist.

Bei anderen Programmen kann und wird das C ++ - Gegenstück in der Regel erheblich schneller ausgeführt als das Java-Äquivalent. Ein von Google im Jahr 2011 durchgeführter Benchmark ergab einen Faktor 10 zwischen C ++ und Java. Im anderen Extrem zeigte ein akademischer Benchmark, der 2012 mit einem 3D-Modellierungsalgorithmus durchgeführt wurde, dass die Java 6- JVM unter Windows 1,09- bis 1,91-mal langsamer als C ++ ist.

Einige Optimierungen, die in Java und ähnlichen Sprachen möglich sind, sind unter bestimmten Umständen in C ++ möglicherweise nicht möglich:

  • C-Stil Zeiger kann Gebrauch behindern in Sprachen , dass die Unterstützung Zeiger zu optimieren,
  • Die Verwendung von Escape-Analysemethoden ist beispielsweise in C ++ eingeschränkt , da ein C ++ - Compiler nicht immer weiß, ob ein Objekt in einem bestimmten Codeblock aufgrund von Zeigern geändert wird.
  • Java kann aufgrund der zusätzlichen Suche nach virtuellen Tabellen in C ++ schneller auf abgeleitete Instanzmethoden zugreifen als C ++ auf abgeleitete virtuelle Methoden. Nicht virtuelle Methoden in C ++ leiden jedoch nicht unter Leistungsengpässen bei V-Tabellen und weisen daher eine ähnliche Leistung wie Java auf.

Die JVM kann auch prozessorspezifische Optimierungen oder Inline-Erweiterungen durchführen . Die Möglichkeit, bereits kompilierten oder eingefügten Code zu deoptimieren, ermöglicht es ihm manchmal, aggressivere Optimierungen durchzuführen als statisch typisierte Sprachen, wenn externe Bibliotheksfunktionen beteiligt sind.

Die Ergebnisse für Mikrobenchmarks zwischen Java und C ++ hängen stark davon ab, welche Operationen verglichen werden. Zum Beispiel beim Vergleich mit Java 5.0:


Anmerkungen

Multi-Core-Leistung

Die Skalierbarkeit und Leistung von Java-Anwendungen auf Mehrkernsystemen wird durch die Objektzuweisungsrate begrenzt. Dieser Effekt wird manchmal als "Zuordnungswand" bezeichnet. In der Praxis verwenden moderne Garbage Collector-Algorithmen jedoch mehrere Kerne, um die Garbage Collection durchzuführen, was dieses Problem bis zu einem gewissen Grad verringert. Es wird berichtet, dass einige Garbage Collectors Zuordnungsraten von über einem Gigabyte pro Sekunde aufrechterhalten, und es gibt Java-basierte Systeme, die keine Probleme bei der Skalierung auf mehrere Hundert CPU-Kerne und Heaps mit einer Größe von mehreren Hundert GB haben.

Die automatische Speicherverwaltung in Java ermöglicht die effiziente Verwendung von sperrenlosen und unveränderlichen Datenstrukturen, die ohne eine Art Speicherbereinigung äußerst schwierig oder manchmal unmöglich zu implementieren sind. Java bietet eine Reihe solcher übergeordneten Strukturen in seiner Standardbibliothek im Paket java.util.concurrent an, während viele Sprachen, die in der Vergangenheit für Hochleistungssysteme wie C oder C ++ verwendet wurden, diese noch nicht haben.

Startzeit

Die Java-Startzeit ist häufig viel langsamer als in vielen Sprachen, einschließlich C , C ++ , Perl oder Python , da viele Klassen (und vor allem Klassen aus den Plattformklassenbibliotheken ) geladen werden müssen, bevor sie verwendet werden können.

Im Vergleich zu ähnlichen gängigen Laufzeiten scheint die Startzeit für kleine Programme, die auf einem Windows-Computer ausgeführt werden, ähnlich wie bei Mono und etwas langsamer als bei .NET zu sein .

Es scheint, dass ein Großteil der Startzeit eher auf E / A-gebundene Operationen (Input-Output) als auf die JVM-Initialisierung oder das Laden von Klassen zurückzuführen ist (die Klassendatendatei rt.jar allein ist 40 MB groß und die JVM muss viele Daten in dieser großen Datei suchen). . Einige Tests zeigten, dass die neue Methode zur Überprüfung des geteilten Bytecodes zwar das Laden von Klassen um etwa 40% verbesserte, bei großen Programmen jedoch nur eine Startverbesserung von etwa 5% erzielte.

Obwohl dies eine kleine Verbesserung ist, ist es in kleinen Programmen, die eine einfache Operation ausführen und dann beenden, sichtbarer, da das Laden von Java-Plattformdaten ein Vielfaches der Last der tatsächlichen Programmoperation darstellen kann.

Ab Java SE 6 Update 10 wird die Sun JRE mit einem Schnellstarter geliefert, der beim Start des Betriebssystems Klassendaten vorlädt, um Daten aus dem Festplatten-Cache und nicht von der Festplatte abzurufen.

Excelsior JET nähert sich dem Problem von der anderen Seite. Der Startoptimierer reduziert die Datenmenge, die beim Start der Anwendung von der Festplatte gelesen werden muss, und macht die Lesevorgänge sequentieller.

Im November 2004 wurde Nailgun , ein "Client, Protokoll und Server zum Ausführen von Java-Programmen über die Befehlszeile ohne JVM-Startaufwand", öffentlich veröffentlicht. Einführung einer Option für Skripte zur Verwendung einer JVM als Dämon zum Ausführen einer oder mehrerer Java-Anwendungen ohne JVM-Startaufwand. Der Nailgun-Daemon ist unsicher: "Alle Programme werden mit denselben Berechtigungen wie der Server ausgeführt." Wenn Mehrbenutzersicherheit erforderlich ist, ist Nailgun ohne besondere Vorsichtsmaßnahmen ungeeignet. Bei Skripten, bei denen der JVM-Start pro Anwendung die Ressourcennutzung dominiert, werden Verbesserungen der Laufzeitleistung um ein bis zwei Größenordnungen angezeigt.

Speichernutzung

Die Speichernutzung von Java ist viel höher als die Speichernutzung von C ++, weil:

  • Es gibt einen Overhead von 8 Bytes für jedes Objekt und 12 Bytes für jedes Array in Java. Wenn die Größe eines Objekts kein Vielfaches von 8 Bytes ist, wird es auf das nächste Vielfache von 8 aufgerundet. Dies bedeutet, dass ein Objekt, das ein Bytefeld enthält, 16 Bytes belegt und eine 4-Byte-Referenz benötigt. C ++ weist außerdem jedem Objekt, das direkt oder indirekt virtuelle Funktionen deklariert , einen Zeiger (normalerweise 4 oder 8 Byte) zu .
  • Mangelnde Adressarithmetik macht das Erstellen speichereffizienter Container wie eng beieinander liegender Strukturen und XOR-verknüpfter Listen derzeit unmöglich ( das OpenJDK Valhalla-Projekt zielt darauf ab, diese Probleme zu mindern, obwohl es nicht darauf abzielt, Zeigerarithmetik einzuführen; Müll gesammelte Umgebung).
  • Im Gegensatz zu malloc und new nähert sich der durchschnittliche Leistungsaufwand der Speicherbereinigung mit zunehmender Heap-Größe asymptotisch Null (genauer gesagt einem CPU-Zyklus).
  • Teile der Java-Klassenbibliothek müssen vor der Programmausführung geladen werden (zumindest die in einem Programm verwendeten Klassen). Dies führt zu einem erheblichen Speicheraufwand für kleine Anwendungen.
  • Sowohl die Java-Binär- als auch die native Neukompilierung befinden sich normalerweise im Speicher.
  • Die virtuelle Maschine verwendet viel Speicher.
  • In Java wird ein zusammengesetztes Objekt (Klasse A, die Instanzen von B und C verwendet) unter Verwendung von Verweisen auf zugewiesene Instanzen von B und C erstellt. In C ++ können die Speicher- und Leistungskosten dieser Arten von Referenzen vermieden werden, wenn die Instanz von B und / oder C existiert innerhalb von A.

In den meisten Fällen verbraucht eine C ++ - Anwendung aufgrund des hohen Overheads der virtuellen Maschine von Java, des Ladens von Klassen und der automatischen Größenänderung des Speichers weniger Speicher als eine entsprechende Java-Anwendung. Für Programme, bei denen der Speicher ein entscheidender Faktor für die Wahl zwischen Sprachen und Laufzeitumgebungen ist, ist eine Kosten-Nutzen-Analyse erforderlich.

Trigonometrische Funktionen

Die Leistung trigonometrischer Funktionen ist im Vergleich zu C schlecht, da Java strenge Spezifikationen für die Ergebnisse mathematischer Operationen enthält, die möglicherweise nicht der zugrunde liegenden Hardwareimplementierung entsprechen. In der x87- Gleitkomma-Teilmenge reduziert Java seit 1.4 die Argumente für sin und cos in der Software, was zu einem großen Leistungseinbruch bei Werten außerhalb des Bereichs führt. JDK (11 und höher) hat im Vergleich zu JDK 8 einen signifikanten Fortschritt bei der Bewertung der trigonometrischen Funktionen erzielt.

Java Native Interface

Die Java Native Interface verursacht einen hohen Overhead, was es kostspielig macht, die Grenze zwischen Code, der auf der JVM ausgeführt wird, und nativem Code zu überschreiten. Java Native Access (JNA) bietet Java- Programmen einfachen Zugriff auf native gemeinsam genutzte Bibliotheken ( Dynamic Link Library (DLLs) unter Windows) nur über Java-Code ohne JNI oder nativen Code. Diese Funktionalität ist vergleichbar mit den ctypes von Windows Platform / Invoke und Python . Der Zugriff ist zur Laufzeit ohne Codegenerierung dynamisch. Aber es hat Kosten und JNA ist normalerweise langsamer als JNI.

Benutzeroberfläche

Swing wurde als langsamer als native Widget-Toolkits angesehen , da es das Rendern von Widgets an die reine Java 2D- API delegiert . Benchmarks, die die Leistung von Swing mit dem Standard Widget Toolkit vergleichen , das das Rendern an die nativen GUI-Bibliotheken des Betriebssystems delegiert, zeigen jedoch keinen eindeutigen Gewinner, und die Ergebnisse hängen stark vom Kontext und den Umgebungen ab. Darüber hinaus behebt das neuere JavaFX- Framework, das Swing ersetzen soll, viele der inhärenten Probleme von Swing.

Verwendung für Hochleistungsrechnen

Einige Leute glauben, dass die Java-Leistung für High Performance Computing (HPC) bei rechenintensiven Benchmarks der von Fortran ähnelt , JVMs jedoch immer noch Probleme mit der Skalierbarkeit für die Durchführung einer intensiven Kommunikation in einem Grid-Computing- Netzwerk haben.

In Java geschriebene Hochleistungs-Computeranwendungen haben jedoch Benchmark-Wettbewerbe gewonnen. In den Jahren 2008 und 2009 konnte ein Apache Hadoop -Cluster (ein in Java geschriebenes Open-Source-Hochleistungsrechnerprojekt) Terabyte und Petabyte von Ganzzahlen am schnellsten sortieren. Das Hardware-Setup der konkurrierenden Systeme wurde jedoch nicht behoben.

In Programmierwettbewerben

Programme in Java starten langsamer als Programme in anderen kompilierten Sprachen. Daher verwenden einige Online-Bewertungssysteme, insbesondere solche, die von chinesischen Universitäten gehostet werden, längere Fristen, damit Java-Programme den Teilnehmern, die Java verwenden, gerecht werden.

Siehe auch

Verweise

Externe Links