java - Android 运行时如何比 CLang C/С++ 编译器 (Android NDK) 更有效地编译 Java?
问题描述
我绝对确信 C\C++ 本机代码将比 Java 代码运行得更快。它是。我的简单 C/C++ 基准测试(int 数组上的随机算术运算)比旧平板电脑(Samsung Galaxy Tab E - Android 4.4.4 - Dalvik VM)上的相同 Java 代码运行速度快 5-7 倍,但在最近的设备上运行速度较慢ART Prestigio K3 Muze (Android 8.1) 和三星 S21 Ultra (Android 11)。
为什么 Android Runtime 编译的代码比原生 C/C++ 代码(Android NDK / JNI)运行得更快?
Java代码:
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++ 代码(JNI):
extern "C" JNIEXPORT void JNICALL Java_com_axiom_firstnative_MainActivity_calculateNative(
JNIEnv* env,
jobject,
jint size) {
int* array = new int[size];
jint sum = 0;
for (jint i=0; i<size; i++) {
array[i] = i;
for (jint j=0; j<size; j++) {
sum += array[i] * array[j];
sum -= sum / 3;
}
}
// delete[] array;
}
OnClick (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);
结果:
三星 Galaxy Tab E (Android 4.4.4) - Java 时间:2166748ns,C/C++ 时间:396729 ns(C/C++ 快 5 倍)
但
Prestigio K3 Muze (Android 8.1) 首次启动 - Java 时间:3477001ns,C/C++ 时间:547692ns(C/C++ 快 6 倍),但预热后 Java 运行速度快 30-40%。
三星 Galaxy S21 Ultra (Android 11) - Java 时间:111000ns,C/C++ 时间:121269ns(Java 首次启动快 9%,预热后快 40-50%!!!)
打开 CLang 编译器优化选项 (-O3) 可使C/C++ 的运行速度 (Android 8.1) 比 Android 运行时优化的 Java 代码快约 30-35%。但是,在Android 11 上,ART 优化代码的运行速度比 CLang C/C++ 优化 (-O3) 本机代码快 10-20%。真是令人心旷神怡……
ps 两个基准测试在一个线程上按顺序运行,所以我想它们使用相同的内核。
问题:
Android 运行时如何编译比 CLang 编译器更高效的原生代码?
在最近的 Android 操作系统版本上编写本机 C/C++ 代码是否有任何性能优势?
解决方案
Android Runtime 如何编译比 CLang (Android NDK) C/C++ 编译器更高效的原生代码?
JIT 编译器补充了 ART 当前的提前 (AOT) 编译器并提高了运行时性能。
尽管 JIT 和 AOT 使用具有相似优化集的相同编译器,但生成的代码可能并不相同。JIT 利用运行时类型信息可以更好地进行内联,并使堆栈替换 (OSR) 编译成为可能,所有这些都会生成略有不同的代码。
在最近的 Android 操作系统版本上编写本机 C/C++ 代码是否有任何性能优势?
对于旧的 Android 设备来说绝对是的。旧的 Android 设备使用解释代码的 Dalvik VM。Java 代码将比 Dalvik VM 上的相同 C/C++ 代码慢 5-7 倍。但在 ART 上,在大多数情况下,Android Runtime profile-guided 编译会根据应用程序执行统计生成更高效的本机代码,但 Java 仍然比 Android 8.1 上的优化 C/C++ 代码慢约 30-35% 和约 10-20%在 Android 11 上更快。
https://source.android.com/devices/tech/dalvik/jit-compiler
结论: 在我看来,为最近的 Android 设备(从 v7.0 Nougat - ART VM 开始)编写 C/C++ 代码并没有性能优势,除非你是一位经验丰富的 C/C++ 开发人员并且深入了解 CPU 架构,所以你可以做比 Android 运行时更好的优化。
此外,Android NDK (C/C++) 仍然是 Android 开发人员的唯一途径:
- 将您的本机 C/C++ 代码移植到 Android。
- 使用 C/C++ 游戏引擎和库(如 Vulkan 或 TensorFlow)。
- 使用 Android SDK 中不可用的特定于平台的 API。
推荐阅读
- java - 如何将 css 文件添加到 Spring Boot 应用程序(Thymeleaf)分页
- c++ - 操作符旁边的参数解包
- ios - 结构“状态”不能用作属性
- r - 如何在 kableExtra 表的某些列中使用数学符号或工程符号?
- flutter - 在 Flutter 中打开启用位置应用设置
- xcode - 如何在 SwiftUI 的启动屏幕中播放视频
- angular - ngx-pagination 对 firestore 收集有效吗?
- java - 如何设置 Java HTTP Server 上下文处理程序线程安全?
- typescript - 打字稿问题循环遍历元组数组并获取特定值
- vue.js - 显示后 textarea 不接受正确的大小 none