Java中为什么要用while,java - 为什么“while(i ++ <n){}”明显慢于“while(++ i <n){}”...

正如其他人所指出的那样,这项测试在很多方面存在缺陷。

您没有告诉我们您是如何进行此测试的。 但是,我试图实现这样的“天真”测试(没有冒犯):

class PrePostIncrement

{

public static void main(String args[])

{

for (int j=0; j<3; j++)

{

for (int i=0; i<5; i++)

{

long before = System.nanoTime();

runPreIncrement();

long after = System.nanoTime();

System.out.println("pre : "+(after-before)/1e6);

}

for (int i=0; i<5; i++)

{

long before = System.nanoTime();

runPostIncrement();

long after = System.nanoTime();

System.out.println("post : "+(after-before)/1e6);

}

}

}

private static void runPreIncrement()

{

final int n = Integer.MAX_VALUE;

int i = 0;

while (++i < n) {}

}

private static void runPostIncrement()

{

final int n = Integer.MAX_VALUE;

int i = 0;

while (i++ < n) {}

}

}

使用默认设置运行时,似乎有一点不同。 但是当你用Integer.MAX_VALUE标志运行时,基准测试的真正缺陷就变得很明显了。 在我的情况下的结果是类似的

...

pre : 6.96E-4

pre : 6.96E-4

pre : 0.001044

pre : 3.48E-4

pre : 3.48E-4

post : 1279.734543

post : 1295.989086

post : 1284.654267

post : 1282.349093

post : 1275.204583

显然,预增量版本已经完全优化了。 原因很简单:结果没有使用。 无论循环是否执行都没关系,因此JIT只是将其删除。

通过查看热点反汇编来确认:预增量版本导致此代码:

[Entry Point]

[Verified Entry Point]

[Constants]

# {method} {0x0000000055060500} 'runPreIncrement' '()V' in 'PrePostIncrement'

# [sp+0x20] (sp of caller)

0x000000000286fd80: sub $0x18,%rsp

0x000000000286fd87: mov %rbp,0x10(%rsp) ;*synchronization entry

; - PrePostIncrement::runPreIncrement@-1 (line 28)

0x000000000286fd8c: add $0x10,%rsp

0x000000000286fd90: pop %rbp

0x000000000286fd91: test %eax,-0x243fd97(%rip) # 0x0000000000430000

; {poll_return}

0x000000000286fd97: retq

0x000000000286fd98: hlt

0x000000000286fd99: hlt

0x000000000286fd9a: hlt

0x000000000286fd9b: hlt

0x000000000286fd9c: hlt

0x000000000286fd9d: hlt

0x000000000286fd9e: hlt

0x000000000286fd9f: hlt

后增量版本导致此代码:

[Entry Point]

[Verified Entry Point]

[Constants]

# {method} {0x00000000550605b8} 'runPostIncrement' '()V' in 'PrePostIncrement'

# [sp+0x20] (sp of caller)

0x000000000286d0c0: sub $0x18,%rsp

0x000000000286d0c7: mov %rbp,0x10(%rsp) ;*synchronization entry

; - PrePostIncrement::runPostIncrement@-1 (line 35)

0x000000000286d0cc: mov $0x1,%r11d

0x000000000286d0d2: jmp 0x000000000286d0e3

0x000000000286d0d4: nopl 0x0(%rax,%rax,1)

0x000000000286d0dc: data32 data32 xchg %ax,%ax

0x000000000286d0e0: inc %r11d ; OopMap{off=35}

;*goto

; - PrePostIncrement::runPostIncrement@11 (line 36)

0x000000000286d0e3: test %eax,-0x243d0e9(%rip) # 0x0000000000430000

;*goto

; - PrePostIncrement::runPostIncrement@11 (line 36)

; {poll}

0x000000000286d0e9: cmp $0x7fffffff,%r11d

0x000000000286d0f0: jl 0x000000000286d0e0 ;*if_icmpge

; - PrePostIncrement::runPostIncrement@8 (line 36)

0x000000000286d0f2: add $0x10,%rsp

0x000000000286d0f6: pop %rbp

0x000000000286d0f7: test %eax,-0x243d0fd(%rip) # 0x0000000000430000

; {poll_return}

0x000000000286d0fd: retq

0x000000000286d0fe: hlt

0x000000000286d0ff: hlt

对我来说,为什么它似乎没有删除后增量版本并不完全清楚。 (事实上,我认为这是一个单独的问题)。 但至少,这解释了为什么你可能会看到“数量级”的差异......

编辑:有趣的是,当将循环的上限从Integer.MAX_VALUE更改为Integer.MAX_VALUE-1时,两个版本都被优化掉并且需要“零”时间。 不知何故,此限制(在程序集中仍显示为0x7fffffff)会阻止优化。 据推测,这与比较被映射到(被烧毁的!)cmp指令有关,但除此之外我无法给出深刻的理由。 JIT以神秘的方式运作......

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值