ein. Wie ist Javas Geschwindigkeit heute im Vergleich zu C ++?
Schwer zu messen. Es ist erwähnenswert, dass ein großer Teil der Geschwindigkeit einer Implementierung, der Speicherzuweiser, sehr unterschiedliche Algorithmen in Java und C ++ sind. Die nicht deterministische Natur des Kollektors macht es im Vergleich zur deterministischen Speicherverwaltung von C ++ äußerst schwierig, aussagekräftige Leistungsdaten zu erhalten, da Sie nie sicher sein können, in welchem Zustand sich der Kollektor befindet. Dies bedeutet, dass es sehr schwierig ist, einen Benchmark zu schreiben das könnte sie sinnvoll vergleichen. Einige Speicherzuweisungsmuster werden mit einem GC viel schneller ausgeführt, andere mit einem systemeigenen Zuweiser.
Was ich jedoch sagen würde, ist, dass der Java GC in jeder Situation schnell laufen muss . Ein nativer Allokator kann jedoch gegen einen geeigneteren ausgetauscht werden. Ich habe kürzlich eine Frage zu SO gestellt, warum ein C # Dictionary
in (0,45 ms auf meinem Computer) im Vergleich zu einem Äquivalent ausgeführt werden kannstd::unordered_map
was auf (10ms auf meinem Rechner) ausgeführt. Durch einfaches Austauschen des Allokators und des Hashers gegen geeignetere habe ich die Ausführungszeit auf meinem Computer auf 0,34 ms verkürzt - ein Dreißigstel der ursprünglichen Laufzeit. Sie könnten niemals hoffen, eine solche benutzerdefinierte Optimierung mit Java durchzuführen. Ein hervorragendes Beispiel dafür, wo dies einen echten Unterschied machen kann, ist das Einfädeln. Native Thread-Bibliotheken wie TBB bieten Thread-Caching-Zuweiser, die bei vielen Zuweisungen für viele Threads erheblich schneller sind als herkömmliche Zuweiser.
Nun werden viele Leute über JIT-Verbesserungen sprechen und wie das JIT mehr Informationen hat. Klar, das stimmt. Aber es ist immer noch nicht annähernd das, was ein C ++ - Compiler abrufen kann, da der Compiler aus der Sicht der Laufzeit des endgültigen Programms vergleichsweise unendlich viel Zeit und Raum zum Ausführen hat. Jeder Zyklus und jedes Byte, für das die JIT sich Gedanken macht, wie Sie Ihr Programm am besten optimieren können, ist ein Zyklus, den Ihr Programm nicht ausführt und für seinen eigenen Speicherbedarf nicht verwenden kann.
Darüber hinaus wird es immer Zeiten geben, in denen Compiler- und JIT-Optimierungen bestimmte Optimierungen nicht nachweisen können - insbesondere bei Dingen wie der Escape-Analyse. In C ++ muss der Compiler den Wert dann nicht ausführen, da er sich ohnehin auf dem Stapel befindet . Darüber hinaus gibt es einfache Dinge wie zusammenhängendes Gedächtnis. Wenn Sie ein Array in C ++ zuordnen, ordnen Sie ein einzelnes, zusammenhängendes Array zu. Wenn Sie ein Array in Java zuordnen, ist es überhaupt nicht zusammenhängend, da das Array nur mit Zeigern gefüllt ist, die irgendwo hinweisen könnten. Dies ist nicht nur ein Speicher- und Zeitaufwand für die doppelten Indirektionen, sondern auch ein Cache-Aufwand. In solchen Fällen erzwingt die Sprachsemantik von Java lediglich, dass sie langsamer sein muss als äquivalenter C ++ - Code.
Letztendlich ist meine persönliche Erfahrung, dass Java im Durchschnitt ungefähr halb so schnell wie C ++ sein kann. Aufgrund der grundlegend unterschiedlichen Algorithmen ist es jedoch realistisch nicht möglich, Leistungsaussagen ohne eine äußerst umfassende Benchmark-Suite zu sichern.
b. Wäre es möglich, mit Java einen modernen AAA-Titel zu erstellen?
Ich nehme an, Sie meinen hier "Spiel" und keine Chance. Erstens müssten Sie alles von Grund auf selbst schreiben, da fast alle vorhandenen Bibliotheken und Infrastrukturen auf C ++ abzielen. Obwohl dies nicht per se unmöglich gemacht wird, könnte es zweifellos einen soliden Beitrag zum Undurchführbaren leisten. Zweitens können selbst die C ++ - Engines kaum in die winzigen Speicherbeschränkungen bestehender Konsolen passen - wenn es für diese Konsolen überhaupt JVMs gibt - und PC-Spieler erwarten ein wenig mehr für ihren Speicher. Das Erstellen performanter AAA-Spiele ist in C ++ schwierig genug. Ich sehe nicht, wie dies in Java erreicht werden könnte. Niemand hat jemals ein AAA-Spiel geschrieben, das viel Zeit in einer nicht kompilierten Sprache verbracht hat. Mehr als das, es wäre einfach extrem fehleranfällig. Deterministische Zerstörung ist unerlässlich, wenn Sie zum Beispiel mit GPU-Ressourcen arbeiten.
c. In welchen Bereichen ist Java, wenn überhaupt, langsamer als C ++? (zB Zahlen, Grafiken oder einfach alles)
Ich würde mich auf jeden Fall für Allround entscheiden. Die erzwungene Referenznatur aller Java-Objekte bedeutet, dass Java weitaus mehr Indirektionen und Referenzen enthält als C ++ - ein Beispiel, das ich zuvor mit Arrays angegeben habe, das jedoch beispielsweise auch für alle Member-Objekte gilt. Wenn ein C ++ - Compiler eine Mitgliedsvariable in konstanter Zeit nachschlagen kann, muss eine Java-Laufzeit einem anderen Zeiger folgen. Je mehr Zugriffe Sie ausführen, desto langsamer wird dies, und das JIT kann nichts dagegen tun.
Während in C ++ ein Teil des Arbeitsspeichers fast sofort freigegeben und wieder verwendet werden kann, muss in Java auf die Auflistung gewartet werden, und ich hoffe, dass dieser Teil nicht den Cache verliert und von Natur aus mehr Arbeitsspeicher benötigt, was eine geringere Cache- und Paging-Leistung bedeutet. Schauen Sie sich dann die Semantik für Dinge wie Boxen und Unboxing an. Wenn Sie in Java auf ein int verweisen möchten, müssen Sie es dynamisch zuordnen. Das ist eine Verschwendung im Vergleich zur C ++ - Semantik.
Dann hast du das Generika-Problem. In Java können Sie generische Objekte nur über die Laufzeitvererbung bearbeiten. In C ++ haben Vorlagen praktisch keinen Overhead - etwas, mit dem Java nicht übereinstimmen kann. Dies bedeutet, dass der gesamte generische Code in Java von Natur aus langsamer ist als ein generisches Äquivalent in C ++.
Und dann kommen Sie zu Undefiniertem Verhalten. Jeder hasst es, wenn sein Programm UB ausstellt, und jeder wünscht, dass es nicht existiert. UB ermöglicht jedoch grundsätzlich Optimierungen, die in Java niemals existieren können. Schauen Sie sich diesen Beitrag an, in dem Optimierungen auf der Basis von UB beschrieben werden. Wenn das Verhalten nicht definiert wird, können Implementierungen mehr Optimierungen vornehmen und den Code reduzieren, der zum Überprüfen auf Bedingungen erforderlich ist, die in C ++ undefiniert, aber in Java definiert sind.
Grundsätzlich schreibt die Semantik von Java vor, dass es eine langsamere Sprache als C ++ ist.
Wird Java jetzt als kompilierte oder interpretierte Sprache betrachtet?
Es passt nicht wirklich in eine dieser Gruppen. Ich würde sagen, dass managed eine separate Kategorie für sich ist, obwohl es definitiv mehr einer interpretierten als einer kompilierten Sprache ähnelt. Noch wichtiger ist, dass es so ziemlich nur zwei große verwaltete Systeme gibt, die JVM und die CLR, und wenn Sie "verwaltet" sagen, ist dies ausreichend explizit.
Was sind einige der Hauptmängel von Java, die seit den Anfängen behoben wurden?
Automatisches Ein- und Auspacken ist das einzige, was ich kenne. Die Generika lösen einige Probleme, aber bei weitem nicht viele.
Was sind einige der Hauptmängel von Java, die noch behoben werden müssen?
Ihre Generika sind sehr, sehr schwach. Die Generika von C # sind erheblich stärker - obwohl es sich natürlich auch nicht um Vorlagen handelt. Deterministische Zerstörung ist ein weiterer großer Mangel. Jede Form von Lambda / Closure ist ebenfalls ein großes Problem - Sie können eine funktionierende API in Java vergessen. Und natürlich gibt es immer das Problem der Leistung für die Bereiche, die sie benötigen.