Java 为什么短基元类型明显比长基元类型或int基元类型慢?
我试图通过将int原语改为short来优化Android游戏的RAM使用。在此之前,我对Java中基本类型的性能感兴趣 所以我用卡钳库创建了这个小测试基准Java 为什么短基元类型明显比长基元类型或int基元类型慢?,java,android,performance,caliper,Java,Android,Performance,Caliper,我试图通过将int原语改为short来优化Android游戏的RAM使用。在此之前,我对Java中基本类型的性能感兴趣 所以我用卡钳库创建了这个小测试基准 public class BenchmarkTypes extends Benchmark { @Param("10") private long testLong; @Param("10") private int testInt; @Param("10") private short testShort;
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;
}
}
public类BenchmarkTypes扩展了Benchmark{
@参数(“10”)专用长测试长;
@参数(“10”)私人内部测试;
@参数(“10”)专用短测试短;
@参数(“5000”)专用长结果长度=5000;
@参数(“5000”)私有int resultInt=5000;
@参数(“5000”)私有短结果短=5000;
@凌驾
受保护的void setUp()引发异常{
Random rand=新的Random();
testShort=(short)rand.nextInt(1000);
testInt=(int)testShort;
testLong=(long)testShort;
}
公共长时间(int代表){
对于(int i=0;i
测试结果令我惊讶
测试环境
在卡尺库下运行基准测试
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;
}
}
测试结果
整数2.365纳秒
长2.436纳秒
短8.156纳秒
测试结论?
短基元类型比长基元和int基元类型慢很多(3-4倍)
问题
Java字节码不支持基本运算(+、-、*、/、>>、>>>,,这是可能的,因为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
)。你没有对JIT进行预热。你没有做足够的迭代。这不是你使用微Bench Java的方式。很可能是这样的由Java将short(每次)转换为int(或long)引起算术operations@GermannArlington-不。对1000倍计时差异的真正解释是基准的编写不正确。请参阅链接的Q&A。没错,这里没有真正的基准!但是速度慢了1000倍?创建一个好的基准真的会产生如此大的差异吗?使用t更新了问题的新测试结果这个答案是正确的。但是,重要的是要记住JVM不会直接执行字节码(一旦它被JIT编译)。因此字节码并不能直接解释差异。例如,如果本机指令集直接支持16算术,并且JIT编译器足够聪明地使用它,那么您可能会期望short
算术比long
算术更快。但实际情况是,用于PC、服务器的指令集甚至智能手机设备也被调整为32位/64位操作,而不是16位操作。因此,执行16位算术通常需要更多的本机指令和更多的时钟周期,这使得它比32位和64位慢…正如OP的基准测试所示。但这高度依赖于目标平台硬件…和可能在JIT编译器上运行。