NDK与JAVA性能比较

11

有没有人能假设使用NDK的C代码与Java代码在相同计算中的速度有多快?(如果有的话)

假设我在Java代码中用Y秒钟进行X个计算(相同的计算)。
通过NDK中的C代码,我可以在相同的Y秒钟内完成多少X计算?
1.2?
2.7?
任意猜测数字?

假设计算公式是B=L/A +C/D(对于所有X个计算都相同)。

编辑:

为什么我要问这个问题?
因为我考虑将我的Java处理摄像头帧移动到C代码中,以获得更大的分辨率机会。

2个回答

21

鉴于没有其他人愿意涉及这个话题,因为认为回答它不太严肃,我来试试:

  • Java编译成字节码,并由JIT将字节码编译成本地代码。
  • C直接编译成本地代码。

区别在于多了一个额外的编译步骤,理论上Java应该比C编译器做得更好,原因如下:

  • Java可以将统计计算插入生成的本地代码中,然后在一段时间后重新生成它以优化针对您代码中当前运行时路径的性能!

然而,Java带来了一些权衡:

  • 需要GC运行来清除内存
  • 可能根本不会JIT代码

GC复制存活对象并扔掉所有死亡对象,由于GC只需处理活着的对象而无需处理死亡对象,理论上比正常的malloc/free循环快。

但是,大多数Java支持者忘记了一件事,那就是在编写C时,并不意味着你必须为每个对象实例都malloc/free。您可以重用内存,可以malloc整个内存块并释放包含数千个临时对象的内存块。

在Java的大堆上,GC时间会增加,添加停顿时间。在某些软件中,当GC清理周期发生时,在定义的毫秒数内使您的软件响应,您将会看到我在说什么。

在一些极端情况下,JIT还可能选择根本不JIT代码。当JIT方法过大时(如果我记得正确,为8K),就会发生这种情况。非JIT方法在运行时的惩罚范围内为20000%(即慢200倍,至少在我们客户那里是这样)。当JVM的CodeCache开始变满时(如果不断地将新类加载到JVM中,这种情况也会发生,也会在客户现场发生),JIT也会关闭。

有一次,JIT统计数据还将一台128核机器的并发性能降到了基本上单核性能。

在Java中,JIT有一定的时间将字节码编译为本机代码,但不可以花费所有的CPU资源用于JIT,因为它与执行程序实际工作的代码并行运行。而在C语言中,编译器可以尽可能长地运行,以生成它认为最优化的代码。这对执行时间没有影响,而在Java中则会有。

我的意思是:

  • Java给你更多,但它的性能不总是由你来决定。
  • C给你更少,但它的性能取决于你如何编写代码。

所以回答你的问题:

  • 选择C并不会使你的程序更快。

如果只使用预分配缓冲区进行简单的数学计算,那么Java和C编译器应该会生成大致相同的代码。


非常感谢您详细的评论。我会仔细阅读它。 - yarin
据我所理解,如果我计算这个表达式:arr[i]=arr1[i]/arr2[2],在这两种情况下所需的时间是相同的吗? - yarin
此外,Java不适合并行编程,因为面向对象编程在这方面表现不佳。另外,Java没有像C++那样好的元编程能力。 - kirill_igum
这个答案很好,但与Android无关。应该说一些关于Android是否允许您使用C++绕过Java的内容。它确实可以。https://dev59.com/X2ox5IYBdhLWcg3w3YD- - kirill_igum
这个答案非常含糊。你知道吗,你的CPU也会在分支预测表中累积统计数据,并且你的代码也会在运行时进行优化。更不用说你的C结构体保证比Java对象等价物更小,因此你可以更好地利用缓存一致性。这个答案没有用真实数据支持任何主张,也没有讲述整个故事。我投反对票。 - jeremyong
也许我的有关Java与NDK性能比较的短期研究会对您有所帮助:https://stackoverflow.com/questions/67423616/how-android-runtime-compiles-java-more-efficiently-than-the-clang-c-%d0%a1-compiler/67454121#67454121 - Bolat Basheyev

7
你可能无法从任何人那里得到一个清晰的答案。这个问题比看起来复杂得多。
在OpenGL中,使用NDK或SDK输出相同数量的多边形没有问题。毕竟,它只是相同的OpenGL调用。渲染多边形(在批处理中)所需的时间远远超过函数调用开销的时间。因此,通常完全可以忽略不计。
但一旦应用程序变得更加复杂并执行一些严肃的计算(AI、场景图管理、剔除、图像处理、数字处理等),本地版本通常会快得多。
还有另一件事:除了当前没有JIT编译的根本问题外。dalvikvm与其编译器似乎非常基本,甚至没有进行任何优化--甚至不是最基本的优化!
有这个(非常好的)视频:Google I/O 2009-为Android编写实时游戏。看完它后,我清楚地知道我肯定会使用带有NDK的C++。
例如:他谈论函数调用的开销,“不要使用函数调用”。...所以是的,我们回到了1970年之前,并开始谈论结构化编程的成本和仅使用全局变量和goto的性能优势。
垃圾收集对游戏来说是一个真正的问题。所以你将花费大量的时间思考如何避免它。即使格式化字符串也会创建新对象。所以有一些提示,比如:不要显示FPS! 如果你懂C++,用new和delete管理内存可能比调整架构以减少/避免垃圾收集更容易。
似乎如果你想编写一个非平凡的实时游戏,你将失去Java所有的优势。不要使用Getter和Setter,不要使用函数调用。避免任何抽象,等等。认真地说?
但回到你的问题:NDK与SDK的性能优势可以从0-10000%不等。这都取决于具体情况。

谢谢你的回答。但是我想做的只是对相机帧进行基本计算,不是游戏,而是视频。只需操作帧并使用FFmpeg进行编码。因此,我考虑在哪里编写“操作”代码。目前我使用Java,所以我考虑将其移植到C语言以获得更好的性能。 - yarin
没有进行任何优化...请参见https://dev59.com/0G445IYBdhLWcg3wWI2L。该答案已经有2.5年的历史了,但是自那以后Dalvik并没有真正发生变化。 - fadden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接