为什么 2 * (i * i) 比 2 * i * i 效率高?| Java Debug 笔记
本文正在参加「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?