我可以从Dalvik和Android工具链中获得什么样的优化?
我正在研究一个高性能的Android应用程序(一个游戏),尽pipe我首先尝试为可读性编写代码,但是我仍然喜欢把脑海中正在发生的事情放在脑海中。 用C ++,我已经开发了一个相当好的直觉了解编译器会做什么,不会为我做什么。 我正在尝试为Java / Android做同样的事情。
因此,这个问题。 在networking上我可以find关于这个话题的很less的东西。 Java编译器,Dalvik转换器(dx)和/或JITter(在Android 2.2+上)会执行如下的优化吗?
-
方法内联。 在什么条件下?
private
方法总是可以安全地内联; 这会完成吗?public final
方法如何? 其他类的对象的方法?static
方法? 如果对象的运行时types可以很容易地被编译器推断出来怎么办? 我应该尽可能将方法声明为final
或static
吗? -
常见的子expression式消除。 例如,如果我访问
someObject.someField
两次,查询是否只做一次? 如果这是一个getter的调用呢? 如果我使用了两次算术expression式呢? 只会评估一次吗? 如果我将某个expression式的结果用作for
循环的上界,那我该怎么办? -
边界检查arrays查找。 工具链会在某些情况下消除这个问题,比如原型循环?
-
价值内联。 将访问到一些
public static final int
总是内联? 即使他们在另一个class级? 即使他们在另一个包裹? -
分支预测。 这个问题甚至有多大? 分支是一个典型的Android设备上的大型性能?
-
简单的算术。 将
someInt * 2
replace为someInt << 1
?
诸如此类……
Ben是JIT @ Google的工程师之一。 当Bill和我开始这个项目时,我们的目标是尽可能快地提供一个可用的JIT,而对资源争用(例如,内存占用,被编译器线程劫持的CPU)影响最小,以便它可以在低端设备上运行好。 因此我们使用了一个非常原始的基于轨迹的模型 也就是说,传递给JIT编译器的编译实体是一个基本块,有时与单个指令一样短。 这些痕迹将在运行时通过称为链接的技术拼接在一起,以便经常不会调用解释器和代码高速caching查找。 在某种程度上,加速的主要来源是消除了频繁执行的代码path上重复的解释器parsing开销。
也就是说,我们在Froyo JIT上实现了不less的本地优化:
- 寄存器分配(8个寄存器用于v5te目标,因为JIT为v7产生Thumb代码/ 16个寄存器)
- 调度(例如Dalvik寄存器的冗余ld / st消除,负载提升,商店下沉)
- 冗余空检查消除(如果这种冗余可以在基本块中find)。
- 简单计数循环的循环形成和优化(即循环体中没有侧向退出)。 对于这样的循环,基于扩展归纳variables的数组访问被优化,以便仅在循环序言中执行空值和范围检查。
- 一个条目在每个虚拟调用站点内嵌caching,并在运行时dynamic修补。
- 窥视孔优化类似于mul / div的文字操作数的降低功率。
在姜饼,我们增加了简单的内联getters / setters。 由于底层JIT前端仍然是简单的基于跟踪的,如果被调用者在那里有分支,它将不会被内联。 但内联caching机制的实现,使虚拟获取/设置可以内联没有问题。
目前我们正在努力扩大编译范围,使编译器有更大的代码分析和优化窗口。 敬请关注。
我相信我的答案不会回答你所有的问题,但是如果答案是一个,我想这是一个胜利。
你似乎对这个问题有深刻的了解,并且知道你想要什么,所以你可能想要做以下事情。 构build一个包含您想要调查的方面的示例应用程序。
把你得到的APK通过APK工具运行。 正如我们所知,逆向工程您自己的代码来完成您所期望的目标是完全正确的。
APK工具将提取和解码您的资源,并将.dex
文件反向工程.smali
文件。 您可能也想查看smali项目,以获取有关如何读取.smali
文件及其局限性的更多信息。
我很确定,这不会回答你所有的问题,但这可能是一个好的开始。
首先,让我先说这个,说我不是达尔维克的专家,我的一些反应可能是错误的。 但是我已经在dalvik中挖掘了JIT代码,并且我对dalvik运行的字节码非常熟悉。
-
方法内联 – 据我所知,这从来没有发生。 我几乎肯定它从来没有发生在字节码级别上,我不认为它现在发生在JIT级别 – 虽然它可能在将来。
-
常见的子expression式消除 – 我相信这只会做不使用任何非最终variables/字段的子expression式。 即使那样,我也不是完全正面的。 如果完成了,我会期望它在字节码级别完成,可能不是JIT级别。
-
对数组查找进行边界检查 – 没有任何线索
-
价值内联 – 据我所知,是的 – 他们将在所有这些情况下内联。
-
分支预测 – 不确定
-
简单的算术 – 并不如我所知
另外,我想提一下另一种方法 – dx和dalvik都是开源的,所以你可以深入挖掘它们。 虽然,它们显然不是小型的代码库,所以在这个级别上花费一点点努力去挖掘它们