使用JNI或不使用JNI(Android性能) [英] To use the JNI, or not to use the JNI (Android performance)

查看:196
本文介绍了使用JNI或不使用JNI(Android性能)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚在正在开发的Android游戏中添加了一些计算量大的代码。所讨论的代码是碰撞检测例程的集合,该例程被频繁调用(游戏循环的每次迭代),并且正在执行大量计算。我觉得我的碰撞检测实现相当完善,并且可以用Java来实现。

I just added some computationally expensive code to an Android game I am developing. The code in question is a collection of collision detection routines that get called very often (every iteration of the game-loop) and are doing a large amount of computation. I feel my collision detection implementation is fairly well developed, and as reasonably fast as I can make it in Java.

我一直在使用 Traceview 来分析代码,而这一新的碰撞检测代码使我的游戏逻辑持续时间翻了一番也就不足为奇了。这显然是一个问题,因为对于某些设备而言,这种性能下降可能会使我的游戏从可玩状态变为无法玩状态。

I've been using Traceview to profile the code, and this new piece of collision detection code has somewhat unsurprisingly doubled the duration of my game logic. That's obviously a concern since for certain devices, this performance hit could take my game from a playable to an unplayable state.

我一直在考虑优化该代码的不同方法,我想知道是否通过将代码移入C ++并使用JNI访问它,是否可以显着节省性能?

I have been considering different ways to optimize this code, and I am wondering if by moving the code into C++ and accessing it with the JNI, if I will get some noticeable performance savings?

以上问题是我的主要关注点,也是提出问题的原因。我确定以下两个原因是使用JNI的其他积极结果。但是,说服我将代码移植到C ++是不够的。

The above question is my main concern and my reason for asking. I've determined that the two following reasons would be other positive results from using the JNI. However, it is not enough to persuade me to port my code to C++.


  • 这将使代码更简洁。由于大多数冲突检测都是某种矢量数学,因此使用重载运算符比使用Java中更多冗长的矢量类要干净得多。

  • This would make the code cleaner. Since most of the collision detection is some sort of vector math, it is much cleaner to be able to use overloaded operators rather than using some more verbose vector classes in Java.

内存管理会更简单。你说简单点吗?好吧,这是一个游戏,因此不欢迎运行垃圾收集器,因为如果GC经常不得不中断清理工作,那么GC最终可能会破坏游戏的性能。在CI中,不必担心垃圾收集器,因此我可以避免使用临时静态变量在Java中做的所有丑陋事情,而只需依靠C ++良好的旧堆栈内存即可。

Memory management would be simpler. Simpler you say? Well, this is a game so the garbage collector running is not welcome because the GC could end up ruining the performance of your game if it constantly has to interrupt to clean up. In C I don't have to worry about the garbage collector, so I can avoid all the ugly things I do in Java with temporary static variables and just rely on the good old stack memory of C++

这个问题可能会引起很大的争议,我想我已经讲完了所有要点。有了这些信息,是否值得将我的代码从Java移植到C ++并使用JNI访问它(出于提高性能的原因)?另外,有没有一种方法可以衡量或估计潜在的性能提升?

Long-winded as this question may be, I think I covered all my points. Given this information, would it be worth porting my code from Java to C++ and accessing it with the JNI (for reasons of improving performance)? Also, is there a way to measure or estimate a potential performance gain?

编辑:

所以我做到了它。结果呢?从TraceView的角度来看,我的碰撞检测例程的速度提高了6倍。

So I did it. Results? Well from TraceView's perspective, it was a 6x increase in speed of my collision detection routine.

到达那里并不容易。除了必须进行JNI跳舞外,我还必须进行一些我没有想到的优化。主要是使用直接分配的浮点缓冲区将数据从Java传递到本机。我最初的尝试只是使用浮点数组来保存有问题的数据,因为从Java到C ++的转换更为自然,但这确实非常慢。直接缓冲区完全避免了Java和本机之间的数组复制带来的性能问题,给我留下了6倍的麻烦。

It wasn't easy getting there though. Besides having to do the JNI dance, I also had to make some optimizations that I did not expect. Mainly, using a directly allocated float buffer to pass data from Java to native. My initial attempt just used a float array to hold the data in question because the conversion from Java to C++ was more natural, but that was realllly reallllly slow. The direct buffer completely side-stepped performance issues with array copying between java and native, and left me with a 6x bump.

此外,我没有使用自己的向量类,而是使用了Eigen数学库。我不确定这会对性能产生多大影响,但是至少,它节省了我开发自己的(效率不高)向量类的时间。

Also, instead of rolling my own vector class, I just used the Eigen math library. I'm not sure how much of an affect this has had on performance, but at the least, it saved me the time of dev'ing my own (less efficient) vector class.

另一个经验教训是,过多的日志记录会降低性能(jic并不明显)。

Another lesson learned is that excessive logging is bad for performance (jic that isn't obvious).

推荐答案

不是确实是您问题的直接答案,但以下链接可能对您有用:

Not really a direct answer to your question, but the following links might be of use to you:

  • Android Developers, JNI Tips.
  • Android Developers, Designing for Performance

在第二个链接中编写如下:

In the second link the following is written:


本地代码不一定比Java更高效。一方面,
会带来与Java原生转换相关的费用,而JIT
无法跨越这些边界进行优化。如果您要分配本机
资源(本机堆上的内存,文件描述符或其他内容),则
安排及时收集
这些资源要困难得多。您还需要为希望运行的每个
架构编译代码(而不是依靠它具有JIT)。
您甚至可能需要为相同结构的
编译多个版本:
G1中为ARM处理器编译的本机代码G1无法充分利用Nexus中的ARM一个,并且在Nexus One中为ARM编译的
代码不会在G1中的ARM上运行。

Native code isn't necessarily more efficient than Java. For one thing, there's a cost associated with the Java-native transition, and the JIT can't optimize across these boundaries. If you're allocating native resources (memory on the native heap, file descriptors, or whatever), it can be significantly more difficult to arrange timely collection of these resources. You also need to compile your code for each architecture you wish to run on (rather than rely on it having a JIT). You may even have to compile multiple versions for what you consider the same architecture: native code compiled for the ARM processor in the G1 can't take full advantage of the ARM in the Nexus One, and code compiled for the ARM in the Nexus One won't run on the ARM in the G1.

当您拥有本地代码时,本机代码主要有用您想要移植到Android的现有本机
代码库,而不是加速 Java应用程序的
部分。

Native code is primarily useful when you have an existing native codebase that you want to port to Android, not for "speeding up" parts of a Java app.

这篇关于使用JNI或不使用JNI(Android性能)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆