繁体   English   中英

为什么短原始类型明显慢于long或int?

[英]Why is the short primitive type significantly slower than long or int?

我尝试通过将int基元更改为short来优化Android游戏的RAM使用率。 在我这样做之前,我对Java中原始类型的性能感兴趣。

所以我使用caliper库创建了这个小测试基准。

public class BenchmarkTypes extends Benchmark {

    @Param("10") private long testLong;
    @Param("10") private int testInt;
    @Param("10") private short testShort;


    @Param("5000") private long resultLong = 5000;
    @Param("5000") private int resultInt = 5000;
    @Param("5000") private short resultShort = 5000;

    @Override
    protected void setUp() throws Exception {
        Random rand = new Random();

        testShort = (short) rand.nextInt(1000);
        testInt = (int) testShort;
        testLong = (long) testShort;
    }

    public long timeLong(int reps){
        for(int i = 0; i < reps; i++){
            resultLong += testLong;
            resultLong -= testLong;         
        }
        return resultLong;
    }

    public int timeInt(int reps){
        for(int i = 0; i < reps; i++){
            resultInt += testInt;
            resultInt -= testInt;           
        }
        return resultInt;
    }

    public short timeShort(int reps){
        for(int i = 0; i < reps; i++){
            resultShort += testShort;
            resultShort -= testShort;
        }
        return resultShort;
    }
}

测试结果让我感到惊讶。

测试环境

基准测试在Caliper库下运行。

检测结果

https://microbenchmarks.appspot.com/runs/0c9bd212-feeb-4f8f-896c-e027b85dfe3b

Int 2.365 ns

长2.436 ns

短8.156 ns

测试结论?

短基元类型比long和int基元类型慢得多(3-4~)?

  1. 为什么短原语明显慢于int或long? 我希望int原语类型在32位虚拟机上最快,长短在时间上相等,或者短到甚至更快。

  2. Android手机也是如此吗? 知道Android手机通常在32位环境中运行,现在越来越多的手机开始配备64位处理器。

Java字节代码不支持小于int的基本类型的基本操作(+, - ,*,/,>>,>>>,<<,%)。 在指令集中没有为这种操作分配字节代码。 因此,VM需要将short(s)转换为int(s),执行操作,然后将int截断为short并将其存储在结果中。

使用javap检查生成的字节代码,以查看short和int测试之间的区别。

VM / JIT优化显然偏向于int / long操作,这是有意义的,因为它们是最常见的。

小于int的类型有其用途,但主要用于在数组中保存内存。 它们不像简单的类成员那样适合(当然,当它适用于数据的类型时,你仍然会使用它们)。 较小的成员甚至可能不会减小对象大小。 当前VM(再次)主要针对执行速度而定制,因此VM甚至可以将字段与本机机器字边界对齐以提高访问性能,但代价是内存花费。

由于java / android处理小于int的基元的整数算术的方式是可能的。

如果在java中添加了两个原语,这些原语的数据类型小于int,则会自动将它们提升为整数数据类型。 通常需要强制转换才能将结果转换回必要的数据类型。

诀窍来自简写操作,如+=-=等,其中演员隐式发生,以便操作的最终结果:

resultShort += testShort;

实际上类似于这样的事情:

resultShort = (short)((int) resultShort + (int) testShort);

如果我们查看方法的反汇编字节码:

public static int test(int a, int b){
    a += b;
    return a;
}

我们看:

public static int test(int, int);
    Code:
       0: iload_0       
       1: iload_1       
       2: iadd          
       3: istore_0      
       4: iload_0       
       5: ireturn   

将此与数据类型的相同方法进行比较,我们得到:

public static short test(short, short);
    Code:
       0: iload_0       
       1: iload_1       
       2: iadd          
       3: i2s           
       4: istore_0      
       5: iload_0
       6: ireturn

注意附加指令i2s (整数到短)。 这可能是性能损失的罪魁祸首。 您可以注意到的另一件事是所有指令都是基于整数的,由前缀i表示(例如, iadd表示整数加)。 这意味着在iload阶段的某个地方,短路被提升为整数,这可能也会导致性能下降。

如果你可以接受我的话,长算术的字节码与整数的字节码相同,但指令是长特定的(例如ladd而不是iadd )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM