关于java性能的一个简单问题。如果我写一个循环
for(int i=0;i<n;++i) buffer[(k++)%buffer.length]=something;
其中某些东西是非平凡的数字滤波器。使用此代码,我在每次写入时都有模数运算。这感觉有点傻,因为无论如何Java VM都会检查它。因此我假设使用ArrayIndexOutOfBounds的consturct会更快(缓冲区包含1'000'000个数字,因此我们不会经常出现溢出)
int i;
try
{
for(i=0;i<n;++i,++k) buffer[k]=something;
}
catch (ArrayIndexOutOfBounds e)
{
k=0;
for(;i<n;++i,++k) buffer[k]=something;
}
第三种解决方案可能是提前计算我们将溢出的点,然后手动将循环分成两部分。每768个样本执行一个确定循环可以走多远的代码,因此从这个角度看它可能比catch方法慢。
这里的问题,除了代码的愚蠢重复,我很乐意在性能的祭坛上牺牲,我们有更多的代码。而且经常会出现java不像小程序那样优化。
所以我的问题是:什么策略是最高效的?有没有人体验过这种类型的构造?此外,任何人都可以了解两种结构的Android设备的性能吗?
答案 0 :(得分:3)
您的答案取决于您的目标平台。你已经添加了Android标签,所以我将以Dalvik和(比方说)Nexus 4来回答。
首先,ARMv7-A架构不提供整数除法指令。你的模数将在每次循环中用软件计算,这会让你慢下来。 (这就是为什么最好对哈希表使用2次幂的大小 - 你可以使用位掩码而不是mod。)
其次,抛出异常是很昂贵的。 VM必须创建异常对象,并使用当前堆栈的快照对其进行初始化。除了直接开销之外,您还要创建X个对象,这些对象必须在以后清理,并增加VM必须在计算中停止并收集垃圾的可能性。
第三,一般来说,你可以从内循环中提取的任何计算代表一个胜利,因此在每次循环迭代时手动测试数组溢出是不令人满意的。如果可以避免,则不希望将k
与length
的测试添加到循环标题或正文中。 (JIT编译器可能会执行类似这样的操作 - 如果它可以告诉数组索引永远不会脱离数组的末尾,则不必执行每元素边界检查。)
基于(仍然有点模糊)你正在做什么以及你做了多少次的感觉,我会说最好的选择是在循环之前计算“中断”位置,然后迭代必要的次数。
我很想知道这在实践中是如何形成的。 : - )