简体   繁体   English

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

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

I tried to optimize the RAM usage of a Android game by changing int primitives to shorts. 我尝试通过将int基元更改为short来优化Android游戏的RAM使用率。 Before I did this I was interested in the performance of the primitive types in Java. 在我这样做之前,我对Java中原始类型的性能感兴趣。

So I created this little test benchmark using the caliper library. 所以我使用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;
    }
}

The results of the test surprised me. 测试结果让我感到惊讶。

Test circumstances 测试环境

Benchmark run under the Caliper library. 基准测试在Caliper库下运行。

Test results 检测结果

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

Int 2.365 ns Int 2.365 ns

Long 2.436 ns 长2.436 ns

Short 8.156 ns 短8.156 ns

Test conclusion? 测试结论?

The short primitive type is significantly slower (3-4~ times) than the long and int primitive type? 短基元类型比long和int基元类型慢得多(3-4~)?

Question

  1. Why is the short primitive significantly slower than int or long? 为什么短原语明显慢于int或long? I would expect the int primitive type to be the fastest on a 32bit VM and the long and short to be equal in time or the short to be even faster. 我希望int原语类型在32位虚拟机上最快,长短在时间上相等,或者短到甚至更快。

  2. Is this also the case on Android phones? Android手机也是如此吗? Knowing that Android phones in general run in a 32bit environment and now the days more and more phones start to ship with 64bit processors. 知道Android手机通常在32位环境中运行,现在越来越多的手机开始配备64位处理器。

Java byte code does not support basic operations (+, -, *, /, >>,>>>, <<, %) on primitive types smaller than int. Java字节代码不支持小于int的基本类型的基本操作(+, - ,*,/,>>,>>>,<<,%)。 There are simply no byte codes allocated for such operations in the instruction set. 在指令集中没有为这种操作分配字节代码。 Thus the VM needs to convert the short(s) to int(s), performs the operation, then truncates the int back to short and stores that in the result. 因此,VM需要将short(s)转换为int(s),执行操作,然后将int截断为short并将其存储在结果中。

Check out the generated byte code with javap to see the difference between your short and int tests. 使用javap检查生成的字节代码,以查看short和int测试之间的区别。

The VM/JIT optimizations are apparently heavily biased towards int/long operations, which makes sense since they are the most common. VM / JIT优化显然偏向于int / long操作,这是有意义的,因为它们是最常见的。

Types smaller than int have their uses, but primarily for saving memory in arrays. 小于int的类型有其用途,但主要用于在数组中保存内存。 They are not as well suited as simple class members (of course you still do use them when its the appropiate type for the data). 它们不像简单的类成员那样适合(当然,当它适用于数据的类型时,你仍然会使用它们)。 Smaller members may not even reduce an objects size. 较小的成员甚至可能不会减小对象大小。 Current VM's are (again) mainly tailored for execution speed, so the VM may even align fields to native machine word boundaries to increase access performance at the expense of memory spend. 当前VM(再次)主要针对执行速度而定制,因此VM甚至可以将字段与本机机器字边界对齐以提高访问性能,但代价是内存花费。

It is possible due to the way java/android handles integer arithmetics with regard to primitives that are lesser than an int. 由于java / android处理小于int的基元的整数算术的方式是可能的。

When two primitives are added in java that are of a datatype that is smaller than an int, they are automatically promoted to the integer datatype. 如果在java中添加了两个原语,这些原语的数据类型小于int,则会自动将它们提升为整数数据类型。 A cast is normally required to convert the result back into the necessary datatype. 通常需要强制转换才能将结果转换回必要的数据类型。

The trick comes with shorthand operations like += , -= and so on where the cast happens implicitly such that the final result of the operation: 诀窍来自简写操作,如+=-=等,其中演员隐式发生,以便操作的最终结果:

resultShort += testShort;

actually resembles something like this: 实际上类似于这样的事情:

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

If we look at the disassembled bytecode of a method: 如果我们查看方法的反汇编字节码:

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

we see: 我们看:

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

comparing this to the identical method with datatype replaced for short we get: 将此与数据类型的相同方法进行比较,我们得到:

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

Notice the additional instruction i2s (integer to short). 注意附加指令i2s (整数到短)。 This is the likely culprit of the loss of performance. 这可能是性能损失的罪魁祸首。 Another thing you can notice is that all instructions are integer-based denoted by the prefix i (eg iadd meaning integer-add). 您可以注意到的另一件事是所有指令都是基于整数的,由前缀i表示(例如, iadd表示整数加)。 Which means somewhere during the iload phase, the shorts were getting promoted to integers which is likely to cause performance degradations as well. 这意味着在iload阶段的某个地方,短路被提升为整数,这可能也会导致性能下降。

If you can take my word for it, the bytecode for long arithmetics is identical to the integer one with exception that the instructions are long-specific (eg ladd instead of iadd ). 如果你可以接受我的话,长算术的字节码与整数的字节码相同,但指令是长特定的(例如ladd而不是iadd )。

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

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