我刚刚为我正在开发的Android游戏添加了一些计算成本高昂的代码。有问题的代码是碰撞检测例程的集合,它们经常被调用(游戏循环的每次迭代)并且正在进行大量的计算。我觉得我的碰撞检测实现相当发达,而且我可以用Java编写它。
我一直在使用Traceview来分析代码,而这条新的碰撞检测代码在某种程度上让游戏逻辑的持续时间翻了一番。这显然是一个值得关注的问题,因为对于某些设备来说,这种性能打击可能会让我的游戏从一个可玩的状态变为一个无法播放的状态。
我一直在考虑不同的方法来优化这些代码,我想知道如果将代码移动到C ++并使用JNI访问它,我是否会获得一些显着的性能节省?
以上问题是我主要关注的问题和我提问的原因。我已经确定以下两个原因是使用JNI的其他积极结果。但是,说服我将代码移植到C ++是不够的。
这会使代码更清晰。由于大多数碰撞检测都是某种向量数学,因此能够使用重载运算符而不是在Java中使用更冗长的向量类更清晰。
内存管理会更简单。你说比较简单吗?好吧,这是一款游戏,因此垃圾收集器运行不受欢迎,因为如果GC不断中断清理,GC最终可能会破坏游戏的性能。在C中我不必担心垃圾收集器,所以我可以避免使用临时静态变量在Java中做的所有丑陋的事情,并且只依赖于C ++的旧旧堆栈内存
这个问题可能是啰嗦,我想我已经涵盖了所有的观点。鉴于此信息,是否值得将我的代码从Java移植到C ++并使用JNI访问它(出于提高性能的原因)?另外,有没有办法衡量或估计潜在的绩效收益?
编辑:
所以我做到了。结果?从TraceView的角度来看,它的碰撞检测程序速度提高了6倍。
虽然到达那里并不容易。除了必须进行JNI舞蹈之外,我还必须进行一些我没想到的优化。主要是,使用直接分配的浮点缓冲区将数据从Java传递到本机。我最初的尝试只是使用一个float数组来保存有问题的数据,因为从Java到C ++的转换更自然,但这真的很慢。直接缓冲完全侧向性能问题与java和本机之间的数组复制,并留下了6倍的凹凸。
另外,我没有使用自己的矢量类,而是使用了Eigen数学库。我不确定这会对性能产生多大影响,但至少可以节省我开发自己(效率较低)矢量类的时间。
另一个经验教训是过度记录对性能有害(jic并不明显)。
答案 0 :(得分:4)
不是您问题的直接答案,但以下链接可能对您有用:
在第二个链接中写下以下内容:
本机代码不一定比Java更有效。一方面, 有与Java本机转换和JIT相关的成本 无法跨越这些边界进行优化。如果您正在分配本机 资源(本机堆上的内存,文件描述符或其他), 安排及时收集可能要困难得多 这些资源。您还需要为每个代码编译代码 你希望运行的架构(而不是依赖它有一个JIT)。 您甚至可能需要为您考虑的内容编译多个版本 相同的架构:为ARM处理器编译的本机代码 G1无法充分利用Nexus One中的ARM和代码 在Nexus One中为ARM编译的ARM不会在G1中运行ARM。
当您拥有现有本机代码时,本机代码非常有用 您希望移植到Android的代码库,而不是用于"加速"部分 一个Java应用程序。
答案 1 :(得分:1)
如果你还处于游戏开发的早期阶段,你可以考虑使用一个提供良好碰撞检测机制的游戏引擎,比如Libgdx,它可以很好地进行box2d碰撞检测。