本文正在参加「Java主题月 – Java Debug笔记活动」,详情查看 活动链接

问题

为什么 2 * (i * i)2 * i * i 效率高?

实行如下代码时,均匀完字节码文件是与渠道无关的二进制码结时刻在 0.50s 到 0.55s 之间:

ublic static void main(String[] args) {
long startjavascriptTime = Sys笔记本电脑性价比排行2020tem.nanoTime();
int n = 0;
for (int i = 0; i < 1000000000; i++) {
n += 2 * (i * i);
}
System.out.println((double) (Syste字节码是什么m.nanoTime() - startTime) / 1笔记本电脑什么牌子好000000000 + " s");
System.out.println("n = " + n);
}

但假如我把其间的笔记本 2 * (i * i) 换成 2 * i * i,程序的均匀结束时刻就在 0.60s 到 0.65s 之间,这是什么原因导致的呢?

我重复运转了上述程序 15 次,每次运转的时刻结字节码和机器码的差异果对比如下java难学吗

2*(i*i)  |  2*i*i
----------+----------
0.5183738 | 0.6246434
0.5298337 | 0.6049722
0.5308647 | 0.6603363
0.5133458 | 0.6243328
0.5003011 | 0.6541802
0.5366181 | 0.6312638
0.515149  | 0.6241105
0.5237389 | 0.627815
0.5249942 |笔记本电脑怎样连wifi 0.6114252
0.56java模拟器41624 | 0.6781033
0.538412  | 0.6393969
0.5466744 | 0.6608845
0.531159  | 0.6201077
0.5笔记本电脑排名前十04java初学8032 | 0.6511559java言语
0.5232789 | 0.6544526

其间运转 2 * i * i 版其他代码最快结束时刻都要比 2 * (i * i) 版别最慢结束时刻慢上许多。假定它们要到达相同的效率,那么此事发生的概率应该低于 1/215∗100%=0.00305%1/2^{15} * 100% = 0.00305%.

答复

答复 1

两者的字节码次序有些许不同。

首要来看 2 * (i * i) 的字节码:

iconst_2
iload笔记本电脑开不了机0
iload0
imul
imul
iadd

再来看 2 * i * i 的字节码:

iconst_2
iload0
imul
iload0
imul
iadd

乍一看,两者并没有什么不同,只是次序发生了变化,但实际上字节码文件第二个java言语版别是更优的版别。

咱们深化底层去看看 JIT,JIT 更倾向于翻开小循环,而 2 * (i * i) 是以 16 倍来翻开的:

030   B2: # B2 B3 &笔记本电脑什么牌子好lt;- B1 B2  Loop: B2-B2 inner main of N18 Freq: 1e+006
030     addl    R11, RBP    # int
033     movl    RBP, R13    # spill
036     addl    RBP, #14    # int
039     imull   RBP, RBP    # int
03cjava言语     mov字节码文件是与渠道无关的二进制码l    R9, R13 # spill
03f     addl    R9, #13 # int
043     imull   R9, R9  # int
047     sall    RBP, #1
049     sall    R9, #1
04c     movl    R8, R13 # spill
04f     addl    R8, #15 # in字节码是什么意思t
053     movl    R10, R8 # spill
056     movdl   XMM1, R8    # spill
05b     imull   R10, R8 # intjava难学吗
05f     movl    R8, R13 # spill
062     addl    R8, #12 # int
06笔记6     imull   R8, R8笔记本电脑连不上无线网怎样回事  # int
06a     sall    R10, #1
06d     movl    [rsp + #32], R10    # spill
072     salljava模拟器    R8, #1
075     movl    RBX, R13    # spill
078     addl    RBX, #11    # int
07b     imull   RBX, RBX    # int
07e     movl    RCX, R13    # spill
081     addl    RCX, #10    # int
084     imull   RCX, RCX    # ijava开发nt
087     sall    RBX, #1笔记本电脑
089     sall    RCX, #1
08b     movl    RDX, R13    # spill
08e     addl    RDX, #8 # int
091     imull   RDX, RDX    # int
094     movl    RDI, R13    # spill
097     a笔记本电脑ddl    RDI, #7 # int
09a     imull   RDI, RDI字节码    # int
09d     sall    RDX, #1
09f     sall    RDI, #1
0a1     movl    RAX, R13    # spill
0a4     addl    RAX, #6 # int
0a7     imull   RAX, RAX    # int
0aa     movl    RSIjava难学吗, R13    # spil字节码文件的扩展名是什么l
0a字节码是虚拟机的机器码d     addl    RSI, #4 # int
0b0     imull   RSIjava言语, RSI    # int
0b3     sall    RAX, #1
0b5     sall    RSI, #1
0b7     movl    R10, R13    # spill
0ba     addl    R10, #2 # int
0be     imull   R10, R10    # int
0c2     mo笔记本电脑什么牌子好vl    R14, R13    # spill
0c5     incl    R14 # int
0c8     imull   R14, R14    # int
0cc     sall    R10, #1
0cf     sall    R14, #1
0d2     addl    R笔记14, R11    # int
0d5     addl    R14, R10    # int
0d8java开发     movl    R10, R13    # spill
0db     addl    R10, #3 # int
0df     imull   R10, R1java模拟器0    # int
0e3     movl    R11, R13    #java怎样读 spill
0e6     addl    R11, #5 # int
0ea     imujava开发ll   R11, R11    # int
0ee     sall    R10, #1
0f1     addl    R10, R14    # int
0f4     addl    R10, RSI    # int
0f7     sall    R11, #1
0fa     addl    R11, R10    # int
0fd     addl    R11, RAX    # int
100     addl    R11, RDI    # int
103     addl    R11, RDX    # int
106     movl    R10, R13    # spill
109     addl    R10, #9 # int
10d     imull   R10, R10    # int
111     sall    R10, #1
114     addl    R10, R11    # int
117     addl    R10, RCX    # in字节码是什么意思t
11a     addl    R10, RBX    # int笔记
11d     addl    R10, R8 # int
120     addl    R9, R10 # int
123     addl    RBP, R9 # int
126     addl    RBP, [RSP + #32 (32-bit)]   #笔记 int字节码文件
12a     addl    R13, #16    # int
12e     movl    R11, R13    # spill
131     imull   R11, R13    # int
135     sall    R11, #1
138     cmpl    R13, #999999985
13f     jl     B2   # loop end  P=1字节码文件.000000 C=6554623.000000

咱们可以看到库房上只需 1 个寄存器溢出。

再来看看 2 * i * i 版别:

05a   B3: # B2 B4 &笔记本lt;- B1 B2  Loop: B3-B2 inner main of N18 Fre字节码和机器码的差异q: 1e+006
05a     addl    RBX, R11    # int
05d     movl    [rsp + #3字节码文件2], RBX    # spi笔记本电脑什么牌子好ll
061     movl    R11, R8 # spill
064     addl    R11, #15    # int
068     mov字节码对象l    [rsp + #36], R11    # spill
06d     mjava开发工程师ovl    R11, R8 # spilljava开发工程师
070     addl    R11字节码, #14    # int
074     movl    R10, R9 # spill
077     addl    R10, #16    # int
07b     movdl   XMM2, R10   # spill
080     movl    RCX, R9 # spill
083     addl    RCX, #14    # int
086     movdl   XMM1, RCX   # spill
08a     movl    R10, R9 # spill
08d     addl    Rjava开发工程师10, #12    # int
091     movdl   XMM4, R10   # spill
096     movl    RCX, R9 # spill
099     addl    RCX, #10    # int
09c     movdl   X字节码文件的扩展名是什么MM6, RCX   # spill
0a0     movl    RB笔记本电脑性价比排行2020X, R9 # spill
0a3     addl    RBX, #8 # int
0a6     movl    RCX, R9 # spill
0a9     addl    RCX, #6 # intjava难学吗
0ac     movl字节码是虚拟机的机器码    RDX, R9 # spill
0af     addl    RDX, #4 # intjavascript
0b2     addl    R9, #2  # int
0b6     movl    R10, R14    # spill
0b9     addl    R10, #22    # int
0bd     movdl   XMM3, R10   # spill
0c2     movl    RDI, R14    # spill
0c5     addl    RDI, #20    # int
0c8     movl    RAX, R14    # spill
0cb     addl    R字节码是什么意思AX, #32    # int
0ce     movl    RSI, R14    # spill
0d1     addl    RSI, #18    # int
0d4     movl    R字节码文件是与渠道无关的什么文件13, R14笔记本电脑连不上无线网怎样回事    # spill
0d7     addl    R13, #24    # int
0db     mo笔记本电脑性价比排行2020v字节码是什么l    R10, R14    # spill
0de     addl    R10, #笔记本电脑开不了机26    # int
0e2     movl    [rsp + #40], R10    # spill
0e7     movl    RBP, R14    # spill
0ea     addl    RBP字节码对象, #28    # int
0ed     imull   RBP, R11    # int
0f1     addl    R14, #30    # int
0f5     imull字节码文件是与渠道无关的什么文件   R14, [RSP + #36 (32-bjavascriptit)]   # int
0fb     mjava面试ovl    R10, R8 # spill
0fe     addl    R10, #11    # int
102     movdl   RJava11, XMM3   # spill
107     imull   R11, R10    # int
10b     movl    [rsp + #44], R11    # spill
110     movl    R10, R8 # spill
113     addl    R10, #10    # int
117     imull   RDI, R10    # int
11b     movl    R11, R8 # spill
11e     addl    R11, #8 # int
1笔记本电脑连不上无线网怎样回事22     movdl   Rjava初学10,笔记本电脑排名前十 XMM2   # spill
127     imujava面试题ll   R10, R11    # i字节码nt
12b     movl    [rsp + #48], R10    # spill
130     movl    R10, R8 # spill
133     addl    R10, #7笔记 # ijava模拟器nt
137     m字节码对象ovdl   R11, XMM1   # spill
13c     i字节码和机器码的差异mjava难学吗ull   R11, R10    # int
140     movl    [rsp + #52], R11    # spill
145     movl笔记    R11, R8 # sp笔记本电脑什么牌子好ill
148     addl    R11, #6 # int
14c     movdl   R10, XMM4   # spill
151     imull   R10, R11    # int
155     movl    [rsp + #56], R10    # spill
15a     movl    R10, R8 # spill
15d     addl    R10, #5 # int笔记本cpu天梯图
161     movdl   R11, XMM6   # spill
166     imull   R11, R10    # int
16a     movl    [rsp + #60], R11    # spill
16f     movl    R11, R8 # spill
172     addl    R11, #4 # int
176     imull   RBX, R11    # int
17a     movjava开发l    R11, R8字节码文件是与渠道无关的二进制码 # spill
17d     addl    R11, #3 # int
181     imull   RCX, R11    # int
185     movl    R10, R8 # spill
188     addl    R10, #2 # int
18c     imull   RDX, R10    # int
190     movl    R11, R8 # spill
1字节码93笔记本电脑怎样连wifi     incljava工作培训班    R11 # int
196     imull   R9, R11 # int
19a     addl    R9, [RSP + #32 (32-bit)]    # int
19f     addl    R9, RDX # int
1a2     addl    R9, RCX # int
1a5     addl    R9, RBX # int
1java言语a8     addl    R9, [RSP + #60 (32-bit)]    #字节码文件的扩展名是什么 int
1ad     addl    R9, [RSP + #56 (32-bit)字节码和机器码的差异]    # int
1b2     addl    R9, [RSP + #52 (32-bit)]    # int
1b7     addl    R9,笔记本电脑怎样连wifi [RSP + #48 (32-bit)]    # int
1bc     movl    R10, R8 # s字节码对象pill
1bf     addl    R10, #9 # int
1c3     imull   R10, RSI    # int
1c7     addl    R10, R9 # int
1ca     addl    R10, RDI    # int
1cd     addl    R10, [RSP + #44 (32-bit)]   # int
1d2     movl    R11, R8 # spill
1d5     addl    R11字节码文件是与渠道无关的什么文件, #12    # int
1字节码是虚拟机的机器码d9     imull   R1java工作培训班3, R11    # int
1dd     addl    R13, R1笔记本电脑开不了机0    # int
1e0     movl    R10, R8 # spil笔记本cpu天梯图l
1e3     addl    R10, #1字节码和机器码的差异3    # int
1e7     imull   R10, [RSP + #40 (32-bit)]   # int
1ed     addl    R10, R13    # int
1f0     addl    RBP, R10    # int
1f3     addl    R14, RBP    # int
1f6     movl    R10, R8 # spill
1f9字节码文件是与渠道无关的二进制码     addl    R10, #16    # int
1fd     cmpl    R10, #999999985
204     jl     B2   # loop end  P=1.000000 C=7419903.000000

这里咱们看到库房上有更多的溢出,这是因为此时需求保存的中心结果增多了。

因而,问题便利的解java模拟器决,java开发2 * (i * i) 之所以比 2 * i * i 效率高,是因为 JIT 为 2 * (i * i) 生成了更佳的汇编代码。

出处

文章翻译自 Stack Overflow:W笔记hy is 2 * (i字节码是什么 * i) faster笔记本电脑什么牌子好 than 2 * i * i in Java?