Android:为什么 native 代码比 Java 代码快这么多

标签 android performance android-ndk jit dalvik

在以下 SO 问题中:https://stackoverflow.com/questions/2067955/fast-bitmap-blur-for-android-sdk @zeh 声称将 Java 模糊算法移植到 C 中运行速度提高了 40 倍。

鉴于大部分代码仅包含计算,并且所有分配仅在实际算法数字运算之前“完成一次”——谁能解释为什么这段代码运行速度快 40 倍? Dalvik JIT 不应该翻译字节码并显着减少与 native 编译代码速度的差距吗?

注意:我自己还没有确认此算法的 x40 性能增益,但我遇到的所有针对 Android 的严肃图像处理算法都在使用 NDK - 因此这支持了 NDK 代码运行速度更快的观点。

最佳答案

对于操作数据数组的算法,有两件事会显着改变 Java 和 C 等语言之间的性能:

  • 数组边界检查:Java 将检查每次访问,bmap[i],并确认i 在数组边界内。如果代码试图越界访问,您将得到一个有用的异常。 C & C++ 不检查任何东西,只信任你的代码。对越界访问的最佳响应是页面错误。更有可能的结果是“意外行为”。

  • 指针:您可以通过使用指针显着减少操作。

以这个普通过滤器(类似于模糊,但是 1D)为例:

for(int i = 0; i < ndata - ncoef; ++i) {  
    z[i] = 0;  
    for(int k = 0; k < ncoef; ++k) {  
        z[i] += c[k] * d[i + k];  
    }  
}  

当您访问数组元素时,coef[k] 是:

  • 将数组coef的地址载入寄存器;
  • 将值k载入寄存器;
  • 对它们求和;
  • 去获取那个地址的内存。

这些数组访问中的每一个都可以改进,因为您知道索引是顺序的。编译器和 JIT 都不知道索引是顺序的,因此它们无法完全优化(尽管它们一直在尝试)。

在 C++ 中,您会编写更像这样的代码:

int d[10000];  
int z[10000];  
int coef[10];  
int* zptr;  
int* dptr;  
int* cptr;  
dptr = &(d[0]); // Just being overly explicit here, more likely you would dptr = d;  
zptr = &(z[0]); // or zptr = z;  
for(int i = 0; i < (ndata - ncoef); ++i) {  
    *zptr = 0; 
    *cptr = coef;  
    *dptr = d + i;  
    for(int k = 0; k < ncoef; ++k) {  
        *zptr += *cptr * *dptr;  
        cptr++;  
        dptr++;  
    }  
    zptr++;  
}  
       

当您第一次做这样的事情(并成功地做到正确)时,您会惊讶于它的速度有多快。所有取索引和索引与基地址求和的数组地址计算都被递增指令代替。

对于图像模糊等二维数组操作,无辜代码 data[r,c] 涉及两次取值,一次乘法和一次求和。因此,对于 2D 数组,指针的优势允许您删除乘法运算。

因此,该语言可以真正减少 CPU 必须执行的操作。代价是 C++ 代码难以阅读和调试。指针错误和缓冲区溢出是黑客的食物。但是当涉及到原始数字磨削算法时,速度的提高太诱人而无法忽视。

关于Android:为什么 native 代码比 Java 代码快这么多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21399257/

相关文章:

android - Android DDMS 中的数据文件夹为空

mysql - 在两个不同的服务器上分析 mysql

android - 如何为 Android 设备的所有体系结构构建 FFMPEG?

android - "dlopen failed: is 32-bit instead of 64-bit"仅在测试中

android - 如何重新启动 Activity 来重新加载静态库?

Android——缩放屏幕布局的常用技巧

Android:网络 radio 在 ACTION_SHUTDOWN 事件之前关闭。事件顺序在 ICS 中更改

android - 在 recyclerview 中保留 edittext 内容

javascript - 什么更快?运行空函数或检查函数是否未定义?

mysql - "don' t 的数据库模式再次向我展示了我之前在 mysql 中看到的内容