Bei der Entwicklung einer Spiele-Engine für Android war ich zuversichtlich, dass nativer C / C ++ - Code schneller ausgeführt werden kann als ähnlicher Java-Code. Diese Aussage ist wahr, aber nicht für die neuesten Versionen von Android. Um zu überprüfen, warum dies geschieht, habe ich mich entschlossen, ein wenig nachzuforschen.
Für den Test wurde Android Studio 4.1.3 verwendet - für Java Android SDK (API 30), für C / C ++ Android NDK (r21, CLang-Compiler). Der Test ist ziemlich dumm und führt arithmetische Operationen an einem int-Array in zwei verschachtelten Schleifen durch. Nichts Sinnvolles und Spezifisches.
Hier ist eine in Java geschriebene Methode:
public void calculateJava(int size) {
int[] array = new int[size];
int sum = 0;
for (int i=0; i<size; i++) {
array[i] = i;
for (int j=0; j<size; j++) {
sum += array[i] * array[j];
sum -= sum / 3;
}
}
}
C/C++ ( Java GC):
extern "C" JNIEXPORT void JNICALL Java_com_axiom_firstnative_MainActivity_calculateNative(
JNIEnv* env,
jobject,
jint size) {
int* array = new int[size];
int sum = 0;
for (int i=0; i<size; i++) {
array[i] = i;
for (int j=0; j<size; j++) {
sum += array[i] * array[j];
sum -= sum / 3;
}
}
// delete[] array;
}
, Java:
long startTime = System.nanoTime();
calculateNative(4096);
long nativeTime = System.nanoTime() - startTime;
startTime = System.nanoTime();
calculateJava(4096);
long javaTime = System.nanoTime() - startTime;
String report = "VM:" + System.getProperty("java.vm.version")
+ "\n\nC/C++: " + nativeTime
+ "ns\nJava: " + javaTime + "ns\n"
+ "\nJava to C/C++ ratio "
+ ((double) javaTime / (double) nativeTime);
Samsung Galaxy Tab E (Android 4.4.4) :
Java time: 2 166 748 ns
C/C++ time: 396 729 ns (C/C++ 5 )
Prestigio K3 Muze (Android 8.1):
Java time: 3 477 001ns ( )
C/C++ time: 547 692ns (C/C++ 6 ),
Java 30-40% (?).
Samsung Galaxy S21 Ultra (Android 11):
Java time: 111 000ns
C/C++ time: 121 269ns
: Java 9% 40-50% C/C++ .
CLang (-O3) C/C++ ~30-35% (Prestigio K3 Muze Android 8.1) Java , .
Smasung Galaxy S21 Ultra (Android 11) Java 10-20% /C++ CLang (-O3). ...
p.s. , , CPU.
, Java Android C/C++ ? ?
. Android Runtime Ahead-of-Time Java , Just-In-Time . . :
The JIT compiler complements ART's current ahead-of-time (AOT) compiler and improves runtime performance. Although JIT and AOT use the same compiler with a similar set of optimizations, the generated code might not be identical. JIT makes use of runtime type information can do better inlining and makes on stack replacement (OSR) compilation possible, all of which generate slightly different code.
Java NDK C/C++ ?
Es scheint mir, dass für alte Geräte mit einer virtuellen Dalvik VM-Maschine (bis Android 7.0) - definitiv ja. Bei neueren Geräten mit Android-Versionen über 7.0 (bei denen die ART-Laufzeit verwendet wird) ist dies nur dann sinnvoll, wenn Sie ein erfahrener C / C ++ - Entwickler sind, der die Funktionsweise der CPU genau versteht und dies kann Optimierungen besser als die Android Runtime. Und das Spiel ist die Kerze nicht wert (Effekt / Anstrengung), außer in den folgenden Fällen:
Sie portieren eine vorhandene C / C ++ - Anwendung auf Android
Sie möchten C / C ++ - Bibliotheken verwenden, die in Java nicht verfügbar sind
Sie möchten APIs verwenden, die im Android SDK nicht verfügbar sind
PS Wenn Sie irgendwelche Gedanken haben, werde ich gerne kommentieren.