Warum könnte Java jemals schneller sein als C ++?


79

Manchmal übertrifft Java C ++ in Benchmarks. Natürlich übertrifft C ++ manchmal.

Siehe die folgenden Links:

Aber wie ist das überhaupt möglich? Es verwirrt mich, dass interpretierter Bytecode jemals schneller sein könnte als eine kompilierte Sprache.

Kann jemand bitte erklären? Vielen Dank!


2
Sie können einen Blick auf nehmen shootout.alioth.debian.org/u32/... die Art von Problemen zu sehen , die auf Java schneller laufen / c ++ ... Sehen Sie das Muster von Problemen, und nicht diese spezifischen Probleme ...
c0da

2
Siehe Warum hatte Java den Ruf, langsam zu sein? für viele Details zu diesem Thema.
Péter Török

11
Es verstößt gegen das Gesetz (Abschnitt 10.101.04.2c), eine Java-VM zu erstellen, die schneller arbeitet als eine mit C ++ erstellte ausführbare Binärdatei.
Mateen Ulhaq

1
@muntoo Was um alles in der Welt meinst du? Abschnitt 10.101.04.2c von was?
Highland Mark

3
@HighlandMark Sie sind kein Mitglied des Kreises. Du sollst nicht wissen, was sich innerhalb des Kreises abspielt. Der Kreis ist absolut - die Gesetze des Kreises haben Vorrang vor denen der Natur. Sie können den Kreis weder herausfordern noch in Frage stellen. Ich bin der Kreis und der Kreis bin ich.
Mateen Ulhaq

Antworten:


108

Erstens enthalten die meisten JVMs einen Compiler, so dass "interpretierter Bytecode" eigentlich ziemlich selten ist (zumindest im Benchmark-Code - es ist nicht ganz so selten im wirklichen Leben, wo Ihr Code normalerweise mehr als ein paar unbedeutende Schleifen enthält, die extrem oft wiederholt werden ).

Zweitens scheint eine ganze Reihe von Benchmarks ziemlich voreingenommen zu sein (ob absichtlich oder inkompetent, kann ich nicht wirklich sagen). Zum Beispiel habe ich mir vor Jahren einen Teil des Quellcodes angesehen, der über einen der von Ihnen geposteten Links verlinkt wurde. Es hatte Code wie folgt:

  init0 = (int*)calloc(max_x,sizeof(int));
  init1 = (int*)calloc(max_x,sizeof(int));
  init2 = (int*)calloc(max_x,sizeof(int));
  for (x=0; x<max_x; x++) {
    init2[x] = 0;
    init1[x] = 0;
    init0[x] = 0;
  }

Da callocder Speicher bereits auf Null gesetzt ist, ist die Verwendung der forSchleife auf Null offensichtlich unbrauchbar. Daraufhin wurde der Speicher (sofern der Speicher belegt ist) ohnehin mit anderen Daten gefüllt (und es bestand keine Abhängigkeit davon, dass sie auf Null gesetzt wurden), sodass das gesamte Nullsetzen ohnehin völlig unnötig war. Das Ersetzen des obigen Codes durch einen einfachen Code malloc(wie es jede vernünftige Person zu Beginn getan hätte) verbesserte die Geschwindigkeit der C ++ - Version so weit, dass sie die Java-Version übertraf (bei ausreichendem Speicherplatz).

Betrachten Sie (für ein anderes Beispiel) den methcallBenchmark, der im Blogeintrag in Ihrem letzten Link verwendet wurde. Ungeachtet des Namens (und wie die Dinge vielleicht sogar aussehen) ist die C ++ - Version davon überhaupt nicht sehr an Methodenaufruf-Overhead interessiert. Der Teil des Codes, der sich als kritisch herausstellt, befindet sich in der Toggle-Klasse:

class Toggle {
public:
    Toggle(bool start_state) : state(start_state) { }
    virtual ~Toggle() {  }
    bool value() {
        return(state);
    }
    virtual Toggle& activate() {
        state = !state;
        return(*this);
    }
    bool state;
};

Der kritische Teil ist der state = !state;. Überlegen Sie, was passiert, wenn wir den Code ändern, um den Status als intstatt als zu codieren bool:

class Toggle {
    enum names{ bfalse = -1, btrue = 1};
    const static names values[2];
    int state;

public:
    Toggle(bool start_state) : state(values[start_state]) 
    { }
    virtual ~Toggle() {  }
    bool value() {  return state==btrue;    }

    virtual Toggle& activate() {
        state = -state;
        return(*this);
    }
};

Diese geringfügige Änderung verbessert die Gesamtgeschwindigkeit um etwa 5: 1 . Obwohl der Benchmark die Methodenaufrufzeit messen sollte, war der größte Teil der Zeit, die gemessen wurde, die Zeit, zwischen intund umzurechnen bool. Ich würde mit Sicherheit zustimmen, dass die Ineffizienz, die das Original zeigt, bedauerlich ist - aber angesichts der Tatsache, wie selten es in echtem Code vorkommt und mit welcher Leichtigkeit es behoben werden kann, wenn / wenn es auftritt, fällt es mir schwer, nachzudenken davon als viel zu bedeuten.

Falls sich jemand entscheidet, die betroffenen Benchmarks erneut auszuführen, sollte ich auch hinzufügen, dass die Java-Version, die produziert wird (oder zumindest einmal produziert wurde - ich habe die Tests mit a nicht erneut ausgeführt), eine fast ebenso triviale Änderung aufweist Jüngste JVMs bestätigen, dass sie dies immer noch tun. Auch in der Java-Version ist dies eine ziemlich wesentliche Verbesserung. Die Java-Version hat ein NthToggle :: activate (), das so aussieht:

public Toggle activate() {
this.counter += 1;
if (this.counter >= this.count_max) {
    this.state = !this.state;
    this.counter = 0;
}
return(this);
}

Wenn Sie dies ändern, um die Basisfunktion aufzurufen, anstatt this.statedirekt zu manipulieren, wird die Geschwindigkeit erheblich verbessert (obwohl dies nicht ausreicht, um mit der modifizierten C ++ - Version Schritt zu halten).

Also, was wir am Ende haben, ist eine falsche Annahme über interpretierte Bytecodes im Vergleich zu einigen der schlechtesten Benchmarks (die ich je gesehen habe). Weder gibt ein aussagekräftiges Ergebnis.

Meine eigene Erfahrung ist, dass C ++ mit ebenso erfahrenen Programmierern, die gleichermaßen auf die Optimierung achten, Java häufiger schlagen wird als nicht - aber (zumindest zwischen diesen beiden) wird die Sprache selten so viel Unterschied machen wie die Programmierer und das Design. Die angeführten Benchmarks sagen mehr über die (In-) Kompetenz / (Dis-) Ehrlichkeit ihrer Autoren aus als über die Sprachen, die sie als Benchmark angeben.

[Bearbeiten: Wie oben an einer Stelle angedeutet, aber nie so direkt angegeben, wie ich es wahrscheinlich hätte tun sollen, sind die Ergebnisse, die ich erhalten habe, als ich dies vor ~ 5 Jahren mit C ++ - und Java-Implementierungen getestet habe, die zu dieser Zeit aktuell waren . Ich habe die Tests mit den aktuellen Implementierungen nicht wiederholt. Ein Blick zeigt jedoch, dass der Code noch nicht repariert wurde. Alles, was sich geändert hätte, wäre die Fähigkeit des Compilers, die Probleme im Code zu vertuschen.]

Wenn wir die Java Beispiele ignorieren, aber es ist tatsächlich möglich , interpretierten Code , schneller zu laufen als kompilierten Code (wenn auch schwierig und etwas ungewöhnlich).

In der Regel ist der zu interpretierende Code viel kompakter als der Maschinencode, oder er wird auf einer CPU ausgeführt, die einen größeren Daten-Cache als der Code-Cache hat.

In einem solchen Fall kann ein kleiner Interpreter (z. B. der innere Interpreter einer Forth-Implementierung) vollständig in den Code-Cache passen, und das Programm, das er interpretiert, passt vollständig in den Daten-Cache. Der Cache ist in der Regel mindestens um den Faktor 10 schneller als der Hauptspeicher und häufig um ein Vielfaches schneller (ein Faktor 100 ist nicht mehr besonders selten).

Wenn der Cache also um den Faktor N schneller als der Hauptspeicher ist und weniger als N Maschinencodeanweisungen erforderlich sind, um jeden Bytecode zu implementieren, sollte der Bytecode gewinnen (ich vereinfache, aber ich denke, die allgemeine Idee sollte es trotzdem sein offensichtlich sein).


26
+1, volle Bestätigung. Insbesondere "die Sprache wird selten so viel Unterschied machen wie die Programmierer und das Design" - Sie werden häufig über Probleme stolpern, bei denen Sie den Algorithmus optimieren können, z.
Schnaader

1
"Falls sich jemand entscheidet, die betroffenen Benchmarks erneut auszuführen ..." NICHT! Im Jahr 2005 wurden diese alten Aufgaben verworfen und durch die Aufgaben ersetzt, die jetzt im Benchmarks-Spiel angezeigt werden. Wenn jemand will , einige Programme dann bitte erneut ausführen , um die laufenden Programme für die aktuellen Aufgaben auf der Benchmarks gezeigt Spiel Homepage neu laufen shootout.alioth.debian.org
igouy

@igouy: Einige Leute möchten vielleicht einfach die Ergebnisse der von ihnen durchgeführten Benchmarks bestätigen / ablehnen, mit dem Minimum an Korrekturen, die erforderlich sind, um ihnen zumindest eine minimale Beziehung zur Realität zu geben. Gleichzeitig haben Sie im Grunde genommen recht: Die fraglichen Benchmarks sind so schlecht, dass es nicht viel hilft, nur die offensichtlichsten Fehler zu beheben.
Jerry Coffin

Deshalb wurden sie 2005 verworfen und durch die Aufgaben ersetzt, die jetzt im Benchmarks-Spiel gezeigt werden. Leute, die es nicht besser wissen, führen diese alten Programme erneut aus.
26.

13
+1 Ich mag es nicht, wenn Leute C ++ im C- oder Java-Stil codieren und dann Java als überlegen bezeichnen. Haftungsausschluss: Ich bezeichne keine Sprache als überlegen, aber wenn man beschissenen C ++ - Code in einem Stil schreibt, der möglicherweise perfekt für eine andere Sprache geeignet ist, sind beide Sprachen nicht vergleichbar.
Christian Rau

111

Handgerolltes C / C ++ , das von einem Experten mit unbegrenzter Zeit ausgeführt wird, ist mindestens so schnell oder schneller als Java. Letztendlich ist Java selbst in C / C ++ geschrieben, so dass Sie natürlich alles tun können, was Java tut, wenn Sie bereit sind, genügend Engineering-Aufwand zu betreiben.

In der Praxis wird Java jedoch häufig aus folgenden Gründen sehr schnell ausgeführt:

  • JIT-Kompilierung - Obwohl Java-Klassen als Bytecode gespeichert sind, wird dieser vom JIT-Compiler (normalerweise) beim Start des Programms zu nativem Code kompiliert. Einmal kompiliert, ist es reiner nativer Code - theoretisch ist also zu erwarten, dass er genauso gut funktioniert wie kompiliertes C / C ++, wenn das Programm lange genug ausgeführt wurde (dh nachdem die JIT-Kompilierung abgeschlossen wurde).
  • Die Garbage Collection in Java ist extrem schnell und effizient - der Hotspot GC ist wahrscheinlich die beste Allround-GC-Implementierung der Welt. Dies ist das Ergebnis jahrelanger Expertenarbeit von Sun und anderen Unternehmen. Ziemlich jedes komplexe Speicherverwaltungssystem, das Sie selbst in C / C ++ ausführen, ist schlechter. Natürlich können Sie in C / C ++ relativ schnelle und leichte grundlegende Speicherverwaltungsschemata schreiben, aber sie sind nicht annähernd so vielseitig wie ein vollständiges GC-System. Da die meisten modernen Systeme ein komplexes Speichermanagement erfordern, hat Java für reale Situationen einen großen Vorteil.
  • Besseres Plattform-Targeting - Durch die Verzögerung der Kompilierung bis zum Start der Anwendung (JIT-Kompilierung usw.) kann der Java-Compiler die Tatsache nutzen, dass er den genauen Prozessor kennt, auf dem er ausgeführt wird. Dies kann einige sehr nützliche Optimierungen ermöglichen, die Sie in vorkompiliertem C / C ++ - Code, der auf einen Prozessorbefehlssatz mit dem niedrigsten gemeinsamen Nenner abzielen muss, nicht durchführen können.
  • Laufzeitstatistik - Da die JIT-Kompilierung zur Laufzeit erfolgt, kann sie während der Ausführung des Programms Statistiken erfassen, die bessere Optimierungen ermöglichen (z. B. die Wahrscheinlichkeit zu kennen, dass eine bestimmte Verzweigung ausgeführt wird). Dies kann Java JIT-Compilern ermöglichen, besseren Code als C / C ++ - Compiler zu erzeugen (die die wahrscheinlichste Verzweigung im Voraus "erraten" müssen, eine Annahme, die oft falsch ist).
  • Sehr gute Bibliotheken - Die Java-Laufzeit enthält eine Vielzahl sehr gut geschriebener Bibliotheken mit guter Leistung (insbesondere für serverseitige Anwendungen). Oft sind diese besser, als Sie selbst schreiben oder für C / C ++ leicht erhalten könnten.

Gleichzeitig hat C / C ++ auch einige Vorteile:

  • Mehr Zeit für erweiterte Optimierungen - Die C / C ++ - Kompilierung wird einmal durchgeführt und kann daher viel Zeit in Anspruch nehmen, wenn Sie erweiterte Optimierungen konfigurieren. Es gibt keinen theoretischen Grund, warum Java nicht das Gleiche tun könnte, aber in der Praxis möchten Sie, dass Java Code relativ schnell JIT-kompiliert, sodass sich der JIT-Compiler in der Regel auf "einfachere" Optimierungen konzentriert.
  • Anweisungen, die in Bytecode nicht ausgedrückt werden können - Java-Bytecode ist zwar allgemein verwendbar, es gibt jedoch einige Dinge, die Sie auf niedriger Ebene nicht in Bytecode ausführen können (ungeprüfte Zeigerarithmetik ist ein gutes Beispiel!). Durch (ab) Verwenden dieser Art von Tricks können Sie einige Leistungsvorteile erzielen
  • Weniger "Sicherheits" -Beschränkungen - Java erledigt einige zusätzliche Arbeiten, um sicherzustellen, dass Programme sicher und zuverlässig sind. Beispiele sind Grenzwertprüfungen für Arrays, bestimmte Garantien für Parallelität, Nullzeigerprüfungen, Typensicherheit für Umwandlungen usw. Wenn Sie diese in C / C ++ vermeiden, können Sie einige Leistungsverbesserungen erzielen (obwohl dies möglicherweise eine schlechte Idee ist!).

Insgesamt:

  • Java und C / C ++ können ähnliche Geschwindigkeiten erreichen
  • C / C ++ hat unter extremen Umständen wahrscheinlich die leichte Kante (es ist nicht verwunderlich, dass AAA-Spieleentwickler es zum Beispiel immer noch bevorzugen)
  • In der Praxis hängt es davon ab, wie sich die verschiedenen oben aufgeführten Faktoren für Ihre spezielle Anwendung auswirken.

9
"Mehr Zeit für Optimierungen in C ++": Dies ist eine der Verbesserungen, die die Oracle-VM bei der Auswahl der Server-VM vornimmt: Sie akzeptiert höhere Startkosten, um langfristig eine höhere Leistung zu ermöglichen. Die Client-VM ist jedoch für eine optimale Startzeit optimiert. Diese Unterscheidung existiert also sogar innerhalb von Java.
Joachim Sauer

8
-1: Ein C ++ - Compiler kann viel mehr Zeit (buchstäblich Stunden für eine große Bibliothek) in Anspruch nehmen, um eine sehr optimierte Binärdatei zu erstellen. Der Java JIT-Compiler kann nicht so viel Zeit in Anspruch nehmen, selbst die "Server" -Version. Ich bezweifle ernsthaft, dass der Java JIT-Compiler in der Lage ist, die vollständige Programmoptimierung wie der MS C ++ - Compiler durchzuführen.
quant_dev

20
@quant_dev: Sicher, aber ist das nicht genau das, was ich in meiner Antwort als C ++ - Vorteil angegeben habe (mehr Zeit für erweiterte Optimierung)? Warum also die -1?
mikera

13
Garbage Collection ist für Java kein Geschwindigkeitsvorteil. Es ist nur ein Geschwindigkeitsvorteil, wenn Sie ein C ++ - Programmierer sind, der nicht weiß, was Sie tun. Wenn Sie nur überprüfen, wie schnell Sie zuweisen können, dann gewinnt der Garbage Collector. Die Gesamtleistung des Programms kann jedoch noch verbessert werden, indem der Speicher manuell verwaltet wird.
Billy ONeal

4
... Aber mit C ++ können Sie theoretisch immer eine "JIT-ähnliche Ebene" erstellen, die zur Laufzeit ähnliche Verzweigungsoptimierungen durchführt, während die Geschwindigkeit eines C ++ - Programms unverändert bleibt. (Theoretisch. :()
Mateen Ulhaq

19

Die Java - Runtime - isnt Bytecode interpretiert. Vielmehr wird das verwendet, was als Just In Time Compilation bezeichnet wird . Grundsätzlich benötigt das Programm beim Ausführen Bytecode und konvertiert ihn in systemeigenen Code, der für die jeweilige CPU optimiert ist.


In der Praxis ja. Im Prinzip kommt es darauf an - Frühe Java Virtual Machines verwendeten Bytecode-Interpreter, und Sie können wahrscheinlich immer noch Bytecode-interpretierende VMs finden, wenn Sie genau genug hinschauen.
Steve314

10
@ Steve314: Aber die rein interpretierenden VMs sind nicht die, die C ++ übertreffen, daher sind sie für diese Frage nicht wirklich relevant.
Joachim Sauer

Der JIT-Compiler kann auch dynamisch für die spezifische Verwendung des Codes optimieren, was bei statisch kompiliertem Code nicht möglich ist.
Starblue

2
@starblue, na ja, mit einer statischen Kompilierung ist das einigermaßen möglich - siehe die profilgeführte Optimierung.
SK-logic

18

Wenn alle Dinge gleich sind, könnte man sagen: Nein, Java sollte niemals schneller sein . Sie könnten Java immer von Grund auf in C ++ implementieren und dadurch mindestens so gute Leistung erzielen. In der Praxis jedoch:

  • JIT kompiliert den Code auf dem Computer des Endbenutzers, sodass er für die genaue CPU optimiert werden kann, auf der er ausgeführt wird. Während es hier einen Overhead für die Kompilierung gibt, kann es sich für intensive Apps auszahlen. Häufig werden reale Programme für die von Ihnen verwendete CPU nicht kompiliert.
  • Der Java-Compiler kann möglicherweise die Dinge besser automatisch optimieren als ein C ++ - Compiler. Oder vielleicht auch nicht, aber in der realen Welt sind die Dinge nicht immer perfekt.
  • Das Leistungsverhalten kann aufgrund anderer Faktoren, z. B. der Speicherbereinigung, variieren. In C ++ rufen Sie den Destruktor normalerweise sofort auf, wenn Sie mit einem Objekt fertig sind. In Java geben Sie einfach die Referenz frei und verzögern die eigentliche Zerstörung. Dies ist ein weiteres Beispiel für einen Unterschied, der in Bezug auf die Leistung weder hier noch da ist. Natürlich können Sie argumentieren, dass Sie GC in C ++ implementieren und damit fertig sein könnten, aber die Realität ist, dass nur wenige Menschen dies tun / wollen / können.

Nebenbei erinnert mich das an die Debatte um C in den 80er / 90er Jahren. Alle fragten sich: "Kann C jemals so schnell sein wie die Montage?" Grundsätzlich lautete die Antwort: Nein auf dem Papier, aber in Wirklichkeit hat der C-Compiler effizienteren Code erstellt als 90% der Assembly-Programmierer (na ja, nachdem er ein bisschen gereift war).


2
In Bezug auf GC kann GC nicht nur die Zerstörung von Objekten verzögern (was auf längere Sicht keine Rolle spielen sollte). Tatsache ist, dass mit den modernen GCs die Zuweisung / Freigabe von kurzlebigen Objekten in Java im Vergleich zu C ++ extrem billig ist.
Péter Török

@ PéterTörök ja du hast recht, guter punkt.
Daniel B

9
@ PéterTörök In C ++ werden jedoch häufig kurzlebige Objekte auf den Stapel gelegt, was wiederum viel schneller ist, als jeder GC-ed-Heap, den Java verwenden kann.
quant_dev

@quant_dev, Sie haben einen weiteren signifikanten GC-Effekt vergessen: die Kompaktifizierung. Ich wäre mir also nicht so sicher, welcher Weg schneller ist.
SK-logic,

3
@DonalFellows Warum müssen Sie sich Gedanken über die Speicherverwaltung in C ++ machen? Die meiste Zeit tue ich nicht. Es gibt einfache Muster, die Sie anwenden müssen und die sich von Java unterscheiden, aber das war's.
quant_dev

10

Die Zuweisung macht jedoch nur die Hälfte der Speicherverwaltung aus - die Freigabe ist die andere Hälfte. Es stellt sich heraus, dass für die meisten Objekte die direkten Kosten für die Speicherbereinigung null betragen. Dies liegt daran, dass ein Kopiersammler keine toten Objekte besuchen oder kopieren muss, sondern nur lebende. Objekte, die kurz nach der Zuweisung zu Müll werden, tragen somit nicht zur Arbeitsbelastung des Erfassungszyklus bei.

...

JVMs sind überraschend gut darin, Dinge herauszufinden, von denen wir bisher angenommen haben, dass nur der Entwickler sie wissen könnte. Wenn die JVM von Fall zu Fall zwischen Stapelzuweisung und Heapzuweisung wählen kann, können wir die Leistungsvorteile der Stapelzuweisung nutzen, ohne dass sich der Programmierer darüber ärgert, ob auf dem Stapel oder auf dem Heap zuzuweisen ist.

http://www.ibm.com/developerworks/java/library/j-jtp09275/index.html


Dies ist nur ein kleiner Teil des Gesamtbildes, aber dennoch ziemlich relevant.
Joachim Sauer

2
Ich mag, wie die Substanz davon ist: Java ist für Noobs, vertraue dem magischen GC, es weiß es besser.
Morg.

1
@Morg: Oder Sie können es so lesen: Java ist für Leute, die Dinge erledigen möchten, anstatt ihre Zeit mit kleinen Änderungen und manueller Speicherverwaltung zu verschwenden.
Landei

4
@Landei Ich denke, Ihr Kommentar hätte viel mehr Glaubwürdigkeit, wenn eine anständige, langlebige und weit verbreitete Codebasis in Java geschrieben worden wäre. In meiner Welt sind echte Betriebssysteme in C geschrieben, PostgreSQL ist in C geschrieben, ebenso wie die wichtigsten Tools, deren Neuschreiben wirklich mühsam wäre. Java war (und das ist sogar die offizielle Version), um weniger erfahrenen Leuten das Programmieren in Herden zu ermöglichen und dennoch greifbare Ergebnisse zu erzielen.
Morg.

1
@Morg Ich finde es sehr seltsam, wie du dich scheinbar nur auf Betriebssysteme konzentrierst. Dies kann aus mehreren Gründen einfach keine gute Maßnahme sein. Erstens unterscheiden sich die Anforderungen von Betriebssystemen grundlegend von den meisten anderen Programmen, zweitens haben Sie das Panda-Daumen-Prinzip (wer möchte ein komplettes Betriebssystem in einer anderen Sprache umschreiben, wer möchte sein eigenes Betriebssystem schreiben, wenn es funktionierende und sogar kostenlose Alternativen gibt?). und drittens verwendet andere Software die Funktionen des Betriebssystems, sodass es nicht erforderlich ist, jemals einen Plattentreiber, Task-Manager usw. zu schreiben. Wenn Sie keine besseren Argumente liefern können (die nicht ausschließlich auf Betriebssystemen basieren), klingen Sie wie ein Hasser.
Landei

5

Während ein vollständig optimiertes Java-Programm ein vollständig optimiertes C ++ - Programm selten übertrifft, können Unterschiede in Sachen Speicherverwaltung viele in Java idiomatisch implementierte Algorithmen schneller machen als dieselben in C ++ idiomatisch implementierten Algorithmen.

Wie @Jerry Coffin betonte, gibt es viele Fälle, in denen einfache Änderungen den Code viel schneller machen können - aber oft sind zu viele unsaubere Anpassungen in der einen oder anderen Sprache erforderlich, damit sich die Leistungsverbesserung lohnt. Das ist wahrscheinlich das, was Sie in einem guten Benchmark sehen würden, der zeigt, dass Java besser abschneidet als C ++.

Auch wenn es normalerweise nicht so wichtig ist, gibt es einige Leistungsoptimierungen, die eine JIT-Sprache wie Java nicht in C ++ durchführen kann. Die Java-Laufzeit kann Verbesserungen enthalten, nachdem der Code kompiliert wurde. Dies bedeutet, dass die JIT möglicherweise optimierten Code erstellen kann, um neue (oder zumindest andere) CPU-Funktionen zu nutzen. Aus diesem Grund kann eine 10 Jahre alte Java-Binärdatei möglicherweise eine 10 Jahre alte C ++ - Binärdatei übertreffen.

Schließlich kann die vollständige Typensicherheit im Großen und Ganzen in sehr seltenen Fällen zu extremen Leistungsverbesserungen führen. Singularity , ein experimentelles Betriebssystem, das fast ausschließlich in einer C # -basierten Sprache geschrieben ist, ermöglicht eine viel schnellere Interprozesskommunikation und Multitasking, da keine Hardware-Prozessgrenzen oder teuren Kontextwechsel erforderlich sind.


5

Gepostet von Tim Holloway auf JavaRanch:

Ein einfaches Beispiel: Wenn Maschinen in mathematisch festgelegten Zyklen betrieben wurden, hatte ein Verzweigungsbefehl normalerweise zwei unterschiedliche Zeitabläufe. Eine für die Zeit, als der Zweig genommen wurde, eine für die Zeit, als der Zweig nicht genommen wurde. Normalerweise war der Fall ohne Verzweigung schneller. Dies bedeutete natürlich, dass Sie die Logik basierend auf dem Wissen optimieren konnten, welcher Fall häufiger vorkommt (unter der Bedingung, dass das, was wir "wissen", nicht immer das ist, was tatsächlich der Fall ist).

Die JIT-Neukompilierung geht noch einen Schritt weiter. Es überwacht die tatsächliche Verwendung in Echtzeit und kippt die Logik basierend auf dem tatsächlich am häufigsten vorkommenden Fall. Und drehen Sie es wieder zurück, wenn sich die Arbeitslast ändert. Statisch kompilierter Code kann dies nicht. Auf diese Weise kann Java manchmal handgestimmten Assembly- / C- / C ++ - Code übertreffen.

Quelle: http://www.coderanch.com/t/547458/Performance/java/Ahead-Time-vs-Just-time


3
Und noch einmal, das ist falsch / unvollständig. Statische Compiler mit profilgeführter Optimierung können dies erkennen.
Konrad Rudolph

2
Konrad, können statische Compiler die Logik basierend auf der aktuellen Arbeitslast umkehren? Soweit ich weiß, generieren statische Compiler Code einmal und dieser bleibt für immer gleich.
Thiago Negri

2
Aktuelle Arbeitsbelastung, Nr. Aber typische Arbeitsbelastung. Die profilgesteuerte Optimierung analysiert, wie Ihr Programm unter typischer Last ausgeführt wird, und optimiert Hotspots entsprechend, wie dies auch beim HotSpot JIT der Fall ist.
Konrad Rudolph

4

Dies liegt daran, dass der letzte Schritt zum Generieren von Maschinencode transparent in der JVM erfolgt, wenn Sie Ihr Java-Programm ausführen, und nicht explizit, wenn Sie Ihr C ++ - Programm erstellen.

Sie sollten die Tatsache berücksichtigen, dass moderne JVMs ziemlich viel Zeit damit verbringen, den Bytecode im laufenden Betrieb zu nativem Maschinencode zu kompilieren, um ihn so schnell wie möglich zu machen. Auf diese Weise kann die JVM alle Arten von Compilertricks ausführen, die noch besser sind, wenn die Profildaten des ausgeführten Programms bekannt sind.

So etwas wie das automatische Inlinen eines Getters, damit kein JUMP-RETURN erforderlich ist, um nur einen Wert zu erhalten, beschleunigt die Dinge.

Das, was wirklich schnelle Programme ermöglicht hat, ist, danach besser aufzuräumen. Der Speicherbereinigungsmechanismus in Java ist schneller als der manuelle Speicherbereinigungsmechanismus in C. Viele moderne Speicherbereinigungsimplementierungen ohne Speicherbereinigung verwenden einen Speicherbereinigungsmechanismus darunter.


Beachten Sie, dass dieses eingebettete Zeug das Starten der JVM größer und langsamer macht, bis der bessere Code die Chance hat, aufzuholen.

1
"Viele moderne malloc-freie Implementierungen verwenden einen darunterliegenden Garbage Collector." "Ja wirklich?" Ich würde gerne mehr wissen. Haben Sie Referenzen?
Sean McMillan

Danke. Ich habe versucht zu sagen, dass die JVM nicht mehr nur einen Just-in-Time-Compiler enthält, der zu ausführbarem Code kompiliert, sondern einen Hot-Spot-Compiler, der den laufenden Code profiliert und dadurch weiter optimiert. Ich einmaliger Compiler wie C ++ kämpft, um das zusammenzubringen.
Highland Mark

@ SeanMcMillan, ich habe vor einiger Zeit eine Analyse über die Leistung von malloc-freien Implementierungen gesehen, in der erwähnt wurde, dass die schnellste einen Garbage Collector darunter verwendete. Ich kann mich nicht erinnern, wo ich es gelesen habe.

War es der BDW konservative GC?
Demi

4

Kurze Antwort - ist es nicht. Vergiss es, das Thema ist so alt wie Feuer oder Rad. Java oder .NET ist und bleibt nicht schneller als C / C ++. Es ist schnell genug für die meisten Aufgaben, bei denen Sie überhaupt nicht an Optimierung denken müssen. Wie Formulare und SQL-Verarbeitung, aber hier endet es.

Für Benchmarks oder kleine Apps, die von inkompetenten Entwicklern geschrieben wurden, ist das Endergebnis, dass Java / .NET wahrscheinlich in der Nähe und vielleicht sogar noch schneller sein wird.

In der Realität wird Java / .NET durch einfache Dinge wie das Zuweisen von Arbeitsspeicher auf dem Stapel oder die Verwendung von Memzonen sofort beendet.

Garbage Collected World verwendet eine Art Memzone für die gesamte Buchhaltung. Füge memzone zu C hinzu und C wird direkt vor Ort schneller sein. Speziell für die Java vs. C "Hochleistungscode" Benchmarks, die so aussehen:

for(...)
{
alloc_memory//Allocating heap in a loop is verrry good, in't it?
zero_memory//Extra zeroing, we really need it in our performance code
do_stuff//something like memory[i]++
realloc//This is lovely speedup
strlen//loop through all memory, because storing string length is soo getting old
free//Java will do that outside out timing loop, but oh well, we're comparing apples to oranges here
}//loop 100000 times

Versuchen Sie, stapelbasierte Variablen in C / C ++ zu verwenden (oder neu zu platzieren). Sie werden übersetzt in sub esp, 0xffeine einzelne x86-Anweisung, die Sie mit Java nicht übertreffen können.

Die meiste Zeit sehe ich die Bänke, auf denen Java gegen C ++ verglichen wird. Falsche Speicherzuweisungsstrategien, selbstwachsende Container ohne Reserven, mehrere neue. Dies kommt dem leistungsorientierten C / C ++ - Code nicht einmal nahe.

Lesen Sie auch Folgendes : https://days2011.scala-lang.org/sites/days2011/files/ws3-1-Hundt.pdf


1
Falsch. Völlig falsch. Mit Ihrer manuellen Speicherverwaltung können Sie einen kompaktifizierenden GC nicht übertreffen. Naives Referenzzählen wird niemals besser sein als ein richtiger Mark'n'Sweep. Sobald es um eine komplizierte Speicherverwaltung geht, ist C ++ eine Verzögerung.
SK-logic

3
@ SK-Logic: Falsch, bei Memzones oder Stack-Zuweisung gibt es KEINE Speicherzuweisung oder Freigabe. Sie haben einen Speicherblock und schreiben einfach darauf. Markieren Sie den Block mit einer flüchtigen Variablen wie InterlockedExchange usw. als frei, und der nächste Thread speichert die Daten nur im vorab zugewiesenen Block, ohne das Betriebssystem nach Speicher zu durchsuchen, sofern er dies für frei hält. Mit Stack ist es noch einfacher, mit der einzigen Ausnahme, dass Sie keine 50 MB auf dem Stack ablegen können. Und diese Objektlebensdauer liegt nur innerhalb von {}.
Coder

2
@ SK-logic: Compiler sind an erster Stelle die Korrektheit, an zweiter Stelle die Leistung. Suchmaschinen, Datenbank-Engines, Echtzeit-Handelssysteme und Spiele sind das, was ich für leistungskritisch halte. Und die meisten von ihnen sind auf flache Strukturen angewiesen. Und so oder so werden Compiler meist in C / C ++ geschrieben. Mit benutzerdefinierten Zuweisern, denke ich. Andererseits sehe ich keine Probleme bei der Verwendung von Baum- oder Listenelementen über Rammap. Sie verwenden einfach die neue Platzierung. Das ist nicht sehr komplex.
Coder

3
@ SK-logic: Es ist nicht viel schneller, jede .NET / Java-App, die ich gesehen habe, erwies sich immer als langsamer und ein echtes Problem. Jedes Umschreiben der verwalteten App in SANE C / C ++ - Code führte zu einer saubereren und leichteren App. Managed Apps sind immer schwer. Siehe VS2010 vs 2008. Gleiche Datenstrukturen, aber VS2010 ist ein HOG. Richtig geschriebene C / C ++ - Apps starten normalerweise in Millisekunden und bleiben nicht auf Begrüßungsbildschirmen hängen, verbrauchen aber auch viel weniger Speicher. Der einzige Nachteil ist, dass Sie Hardware im Auge behalten müssen und viele Leute nicht wissen, wie es heutzutage ist. Es sind nur Benchmarks, bei denen man eine Chance hat.
Coder

2
Ihre anekdotischen Beweise zählen nicht. Richtige Benchmarks zeigen den wirklichen Unterschied. Es ist besonders seltsam, dass Sie sich auf die GUI-Anwendungen beziehen, die an die sperrigen und suboptimalen GUI-Bibliotheken gebunden sind. Und was noch wichtiger ist: Theoretisch ist die Leistungsgrenze für einen ordnungsgemäß implementierten GC viel höher.
SK-logic

2

Die Realität ist, dass beide nur hochrangige Assembler sind, die genau das tun, was der Programmierer ihnen befiehlt, genau so, wie der Programmierer es ihnen befiehlt, in der genauen Reihenfolge, in der der Programmierer es ihnen befiehlt. Die Leistungsunterschiede sind so gering, dass sie für alle praktischen Zwecke unerheblich sind.

Die Sprache ist nicht "langsam", der Programmierer hat ein langsames Programm geschrieben. Sehr selten wird ein Programm, das in einer Sprache am besten geschrieben ist, besser sein als ein Programm (zu irgendeinem praktischen Zweck), bei dem das Gleiche auf die beste Art und Weise der alternativen Sprache getan wird, es sei denn, der Autor der Studie ist bestrebt, seine spezielle Axt zu schleifen.

Wenn Sie sich in seltenen Fällen wie Echtzeit-Embedded-Systemen befinden, kann die Sprachauswahl natürlich einen Unterschied machen. Aber wie oft ist dies der Fall? und von diesen Fällen ist, wie oft die richtige Wahl nicht blind offensichtlich.


2
In der Theorie ein „ideal“ JITting VM muss übertrifft statisch kompilierten Code, durch seine Optimierungen an die dynamisch gesammelt Profilinformationen anzupassen. In der Praxis sind JIT-Compiler noch nicht so schlau, aber sie sind zumindest in der Lage, einen Code mit einer ähnlichen Qualität wie bei ihren größeren und langsameren statischen Peers zu erstellen.
SK-logic

2

Siehe die folgenden Links ... Aber wie ist das überhaupt möglich? Es verwirrt mich, dass interpretierter Bytecode jemals schneller sein könnte als eine kompilierte Sprache.

  1. Liefern diese Blog-Posts vertrauenswürdige Beweise?
  2. Liefern diese Blogbeiträge endgültige Beweise?
  3. Liefern diese Blogeinträge überhaupt Beweise für "interpretierten Bytecode"?

Keith Lea sagt, dass es "offensichtliche Mängel" gibt, unternimmt aber nichts gegen diese "offensichtlichen Mängel". Im Jahr 2005 wurden diese alten Aufgaben verworfen und durch die Aufgaben ersetzt, die jetzt im Benchmarks-Spiel angezeigt werden .

Keith Lea sagt, dass er "den Benchmark-Code für C ++ und Java aus dem mittlerweile veralteten Great Computer Language Shootout genommen und die Tests durchgeführt hat", aber tatsächlich zeigt er nur Messungen für 14 von 25 dieser veralteten Tests an .

Keith Lea sagt Ihnen jetzt, dass er vor sieben Jahren mit dem Blog-Post nichts zu beweisen versucht hat, aber damals sagte er: "Ich hatte es satt, Leute sagen zu hören, Java sei langsam, wenn ich weiß, dass es ziemlich schnell ist ...", was darauf hindeutet Damals gab es etwas, was er zu beweisen versuchte.

Christian Felde sagt: "Ich habe den Code nicht erstellt, sondern nur die Tests wiederholt." Als ob dies ihn von jeder Verantwortung für seine Entscheidung entbunden hätte, Messungen der von Keith Lea ausgewählten Aufgaben und Programme zu veröffentlichen.

Liefern Messungen von nur 25 winzigen Programmen endgültige Beweise?

Diese Messungen gelten für Programme, die im "gemischten Modus" ausgeführt werden. Java wird nicht interpretiert . Sie können leicht herausfinden, wie gut Java "interpretierten Bytecode" ausführt, da Sie Java zwingen können, nur Bytecode zu interpretieren - einfach einige Java-Programme mit und ohne die Option -Xint ausführen.


-1

Es amüsiert mich, wie allgegenwärtig diese seltsame Vorstellung von "interpretiertem Bytecode" ist. Haben Sie schon einmal von der JIT-Zusammenstellung gehört? Ihr Argument kann nicht auf Java angewendet werden.

Wenn man JVM beiseite lässt, gibt es Fälle, in denen ein direkter Thread-Code oder sogar eine triviale Bytecode-Interpretation einen stark optimierten nativen Code leicht übertreffen können. Die Erklärung ist recht einfach: Bytecode kann recht kompakt sein und passt in Ihren kleinen Cache, wenn eine native Codeversion desselben Algorithmus mehrere Cache-Fehler für eine einzelne Iteration aufweist.


Die Verbreitung der Interpretation ist möglicherweise auf Menschen zurückzuführen, die sich in der Informatik auskennen. Die Java Virtual Machine ist eine Maschine, die Java-Bytecode akzeptiert und auf einer Maschine ausführt, auf der Java-Bytecode nicht ausgeführt werden kann, ohne ein funktional gleichwertiges natives Programm schreiben zu können. Ergo ist es ein Dolmetscher. Sie können den Zwischenspeichertechniken jeden Namen geben, den Sie sich vorstellen können, JIT oder auf andere Weise, aber es handelt sich um einen Interpreter gemäß der Definition von Interpreter.
Thiton

@thiton, die Chancen stehen gut, dass dein CS-Fu ein bisschen schwach ist. JVM keine Art von Interpretation tun (für Hot Spots) - als jemand, der CS wagen zu erwähnen, Sie haben zu wissen , was es bedeutet, und wie eine operationale Semantik einer Interpretation unterscheidet sich von einem nativen Code ausgeführt wird . Aber wahrscheinlich kennen Sie CS einfach nicht genug, um Kompilierung von Interpretation zu unterscheiden.
SK-logic

2
Umm, aber der Bytecode muss in nativen Code konvertiert werden, damit er ausgeführt werden kann. Sie können der CPU keinen Java-Bytecode zuführen. Das Größenargument ist also ungültig.
quant_dev

@quant_dev, natürlich - ich sagte, dass dieser Fall absolut nichts mit JVM zu tun hat. Sie benötigen eine viel einfachere Bytecode-Engine, um diesen Effekt zu erzielen.
SK-logic

-1

Abgesehen von JIT, GC usw. kann C ++ sehr, sehr leicht langsamer gemacht werden als Java. Dies wird in Benchmarks nicht angezeigt, aber dieselbe App, die von Java-Entwicklern und C ++ - Entwicklern geschrieben wurde, ist in Java möglicherweise viel schneller.

  • Bedienerüberladung. Jeder einfache Operator wie "+" oder "=" kann Hunderte von Codezeilen aufrufen, um Sicherheitsüberprüfungen, Datenträgeroperationen, Protokollierung, Verfolgung und Profilerstellung durchzuführen. Und sie sind so einfach zu bedienen, dass Sie die Operatoren, sobald Sie sie überlastet haben, auf natürliche Weise und reichlich verwenden, ohne zu bemerken, wie sich die Nutzung entwickelt.
  • Vorlagen. Diese wirken sich weniger auf die Geschwindigkeit als auf den Speicher aus. Die unachtsame Verwendung von Vorlagen führt dazu, dass Millionen von Codezeilen (Alternativen zur Basisvorlage) generiert werden, ohne dass Sie dies jemals bemerken. Aber dann binäre Ladezeiten, Speicherauslastung, Auslagerungsauslastung - all das wirkt sich auch gegen Benchmarks aus. Und die RAM-Nutzung geht durch das Dach.

Was fortgeschrittene Vererbungsmuster betrifft, so sind diese ziemlich ähnlich - C ++ hat einige, die Java nicht hat, und umgekehrt, aber alle von ihnen verursachen auch einen ähnlichen, signifikanten Overhead. Also kein besonderer C ++ Vorteil bei objektlastiger Programmierung.

Eine weitere Einschränkung: GC kann schneller oder langsamer sein als das manuelle Verwalten von Zuweisungen. Wenn Sie viele kleine Objekte zuweisen, wird in der GC-Umgebung normalerweise ein Teil des Arbeitsspeichers zugewiesen und Teile davon werden bei Bedarf für neue Objekte verteilt. In verwaltet - jedes Objekt = separate Zuordnung benötigt erhebliche Zeit. OTOH, wenn Sie viel Speicher auf einmal malloc () und dann Teile davon manuell Ihren Objekten zuweisen oder nur wenige größere Instanzen von Objekten verwenden, können Sie viel schneller auftauchen.


4
Ich bin mit beiden Punkten nicht einverstanden. Ob Sie Operatoren oder Methoden verwenden, ist unerheblich. Sie sagen, dass sie sich vermehren werden. Unsinn - nicht mehr als Methoden; Sie müssen sie entweder anrufen oder nicht. Und Vorlagen führen zu nicht mehr Code, als diesen bestimmten Code zur mehrfachen Verwendung erneut von Hand zu schreiben. Möglicherweise ist mehr Code als beim Runtime-Versand (virtuelle Funktionen) vorhanden, aber auch dies ist irrelevant: Die Leistung der Befehls-Cache-Zeilen ist in engen Schleifen am wichtigsten, und hier wird nur eine Vorlageninstanziierung verwendet, sodass kein relevanter Speicherdruck besteht aufgrund von Vorlagen.
Konrad Rudolph

Die übliche Denkweise ist, dass Methoden teuer und Betreiber billig sind. Sie verwenden Methoden, wenn Sie müssen, Operatoren, wenn Sie Zeit sparen und optimieren möchten. Es ist keine technische Angelegenheit, sondern eine psychologische - es ist nicht so, dass Bediener "schwerer" sind, sie sind einfach viel einfacher zu bedienen und werden viel häufiger verwendet. (Außerdem können Sie einen häufig verwendeten Operator in einem bereits vorhandenen Code überladen, so dass er den gleichen Vorgang wie im Original ausführt, sowie einen zusätzlichen - und plötzlich verlangsamt sich der gesamte Code erheblich.
SF.

Ich bestreite, dass diese psychologische Tatsache real ist, und selbst wenn dies der Fall ist, haben Sie nicht die Wahl : Wenn Sie eine Funktionalität benötigen, verwenden Sie sie, unabhängig davon, ob sie in einem Operator oder einer Methode verkapselt ist. Die Psychologie ist für Ihre Wahl der Semantik unerheblich.
Konrad Rudolph

1
Fangfrage. Ich würde das überhaupt nicht nachvollziehen, ich würde messen, dann handeln . Ich hatte noch nie ein Problem mit dieser Taktik.
Konrad Rudolph

1
@KonradRudolph: Dies ist alles wahr, wenn es um Klarheit und einfache Erstellung des Codes geht, der fehlerfrei und wartbar ist. Der Punkt über die Effizienz der Algorithmusimplementierung bleibt jedoch bestehen: Wenn Sie obj.fetchFromDatabase("key")drei Mal innerhalb von fünf Codezeilen für denselben Schlüssel schreiben , werden Sie zweimal überlegen, ob Sie diesen Wert einmal abrufen und in einer lokalen Variablen zwischenspeichern möchten. Wenn Sie obj->"key"mit ->Überlastung schreiben , um als Datenbankabruf zu fungieren, sind Sie viel anfälliger dafür, sie einfach passieren zu lassen, da die Kosten des Vorgangs nicht offensichtlich sind.
SF.

-2

Irgendwie nimmt Stack Exchange meine anderen Stackpoints nicht an, also ... leider keine Antwort ...

Die am zweithäufigsten gewählte Antwort hier ist meiner bescheidenen Meinung nach jedoch voller Fehlinformationen.

Eine handgerollte App von einem Experten für C / C ++ ist IMMER viel schneller als eine Java-Anwendung. Es gibt kein "so schnell wie Java oder schneller". Es ist nur schneller, gerade wegen der Artikel, die Sie unten zitieren:

JIT-Kompilierung : Erwarten Sie wirklich, dass ein automatischer Optimierer die Intelligenz eines erfahrenen Programmierers besitzt und den Zusammenhang zwischen der Absicht und dem Code erkennt, den die CPU wirklich ausführen wird? Darüber hinaus ist alles, was Sie tun, Zeitverlust im Vergleich zu einem bereits kompilierten Programm.

Garbage Collection ist ein Tool, mit dem Ressourcen, deren Zuordnung ein Programmierer vergessen hätte, mehr oder weniger effizient freigegeben werden.

Offensichtlich kann dies nur langsamer sein als das, was ein Experte (Sie haben den Begriff gewählt) C-Programmierer tun würde, um mit seinem Speicher umzugehen (und nein, es gibt keine Lecks in korrekt geschriebenen Apps).

Eine leistungsoptimierte C-Anwendung kennt die CPU, auf der sie ausgeführt wird, sie wurde kompiliert. Das heißt, Sie haben nicht alle Schritte für die Leistung unternommen, oder?

Laufzeitstatistik Ich bin mir nicht sicher, aber ich vermute, dass ein Experte in C über mehr als genug Branchenvorhersagewissen verfügt, um die automatisierte Optimierung erneut zu überlisten.

Sehr gute Bibliotheken Es gibt viele nicht sehr optimierte Funktionen, die über Bibliotheken in Java verfügbar sind, und das Gleiche gilt für jede Sprache. Die am besten optimierten Bibliotheken sind jedoch in C geschrieben, insbesondere für Berechnungen.

Die JVM ist eine Abstraktionsebene, die sowohl Vorteile impliziert, von denen viele übergeordnet sind, als auch impliziert, dass die Gesamtlösung vom Design her langsamer ist.

Insgesamt:

Java kann niemals die Geschwindigkeit von C / C ++ erreichen, da es in einer JVM mit vielen Schutzfunktionen, Funktionen und Tools funktioniert.

C ++ hat einen klaren Vorsprung bei optimierter Software, sei es für Computer oder Spiele, und es ist üblich zu sehen, dass C ++ - Implementierungen Codierungswettbewerbe gewinnen, bis zu dem Punkt, dass die besten Java-Implementierungen nur auf der zweiten Seite zu sehen sind.

In der Praxis ist C ++ kein Spielzeug und lässt Sie nicht mit vielen Fehlern davonkommen, mit denen die meisten modernen Sprachen fertig werden können. Durch seine Einfachheit und Sicherheit ist es jedoch von Natur aus schneller.

Und als Fazit möchte ich sagen, dass die meisten Leute nicht zwei Cent dafür ausgeben, dass Optimierung letztendlich ein Sport ist, der nur wenigen glücklichen Entwicklern vorbehalten ist und das, außer in Fällen, in denen es wirklich um Leistung geht (Wenn Sie die Hardware mit 10 multiplizieren, hilft dies nichts - oder es sind mindestens ein paar Millionen), bevorzugen die meisten Manager eine nicht optimierte App und eine Tonne Hardware.


Nochmal. Garbage Collection ist nicht nur ein "Tool, das die Zuordnung aufhebt". GC kann Ihre Strukturen verdichten. GC kann mit Ihren schwachen Referenzen umgehen und Ihnen dabei helfen, Ihr Caching auf diese Weise auszugleichen. Multistage GC macht eine Heap-Zuordnung viel billiger als Ihre sperrigen, langsamen newoder malloc(). Es kann im Allgemeinen viel schneller sein als jede manuelle Speicherverwaltung, da Sie Objekte nicht manuell verschieben können. Alle Ihre Überlegungen sind also eindeutig falsch und voreingenommen. Ihre Kenntnisse über GC-Algorithmen und JIT-Optimierungsmethoden sind zu begrenzt.
SK-logic

4
Diese Antwort steckt voller Missverständnisse darüber, was moderne Optimierer tun können. Handoptimierter Code hat dagegen keine Chance. Aber dann, C ++ auch hat einen optimierenden Compiler.
Konrad Rudolph

Vielen Dank für Ihren Kommentar SK-logic, aber wie Sie sagen, kann der GC im Allgemeinen viel schneller sein, wir sprechen über den schnellsten in einem bestimmten Fall, und es scheint, dass die meisten Menschen zustimmen, dass der GC alles kann Das kann ein Programmierer und noch besser. Natürlich können Sie Objekte manuell verschieben, wenn Sie direkten Speicherzugriff haben. Lol. Mein Wissen über die JVM-Interna ist sicher begrenzt und ich erwarte von Java-Köpfen, dass sie mir das Licht zeigen, und nicht nur zufälligen Mist darüber, dass der GC Dinge kann, die man nicht manuell machen kann (lol ... sogar der GC muss benutze die CPU Anleitung;)).
Morg.

Konrad, ich stimme zu, dass ich moderne Optimierer weitgehend unterschätze ... ich finde es jedoch interessant, dass Sie handoptimierten Code als schlechter als automatisch optimierten Code ansehen. Was genau erwarten Sie vom Compiler, das ein Mensch nicht sehen kann?
Morg.

1
Richtig . Drücken Sie weiter -1, das ändert nichts an der Tatsache, dass C ++ schneller als Java ist. Ich weiß vielleicht nicht viel über moderne Compiler, aber das macht keinen Unterschied zum Hauptpunkt, der korrekt ist und der hier am häufigsten gewählten Antwort widerspricht. Warum sollte C ++ für nVidia bei den GPUs für HPC Priorität haben? Warum sollten alle Spiele in C ++ geschrieben werden, warum sollte jede einzelne DB-Engine in C geschrieben werden?
Morg.

-4

Ich habe mindestens zwei beeindruckende MMOs in Java gesehen, zu sagen, dass es für Spiele nicht schnell genug ist, ist eine falsche Bezeichnung. Nur weil Spieleentwickler C ++ gegenüber anderen Sprachen bevorzugen, heißt das, dass es nicht nur mit Java zusammenhängt, sondern dass Programmierer sich noch nie wirklich mit anderen Programmiersprachen / -paradigmen beschäftigt haben. Jede Sprache, die so fortgeschritten ist wie C / C ++ oder sogar Java, kann Code erzeugen, der das Argument Geschwindigkeit technisch erfüllen oder zunichte machen kann. Das alles hängt davon ab, was Programmierer wissen, mit welchen Teams sie am meisten arbeiten und vor allem, warum sie diese Tools verwenden. Da wir uns mit dem Spielentwicklungsaspekt der Programmierung befassen, muss das Argument mehr beinhalten. Einfach gesagt ' Es dreht sich alles um Geld und Zeit für ein Unternehmen, das darauf aus ist, Tools zu verwenden, die der Qualitätssicherung entsprechen, und in der Praxis spielt es keine Rolle, warum xx Gründe für die Wahl von C ++ gegenüber Java oder einer anderen Sprache ausschlaggebend sind. Es ist nur eine Massenproduktionsentscheidung. Auf der grundlegendsten Ebene der Rechenalgorithmen spielen wir nur mit Einsen und Nullen. Das Geschwindigkeitsargument ist eines der dümmsten Argumente, die jemals auf Spiele angewendet wurden. Wenn Sie Geschwindigkeitszuwächse wünschen, lassen Sie die Programmiersprachen ganz fallen und arbeiten Sie mit Assemblern, die bei weitem der beste Vorteil sind.


2
Diese Textwand scheint nichts hinzuzufügen, was in den anderen Antworten nicht bereits angegeben wurde. Bitte bearbeiten Sie Ihre Antwort besser lesbar zu sein, und bitte stellen Sie sicher , dass Ihre Antwort - Adressen durch die andere Antwort Punkte nicht erhoben. Andernfalls sollten Sie Ihre Antwort löschen, da an dieser Stelle nur noch Rauschen zu hören ist.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.