Java之深入JVM(1) - 由i++ 和 ++i的执行速度所想到的
2013-06-11 20:53
323 查看
Code
public class Increment {
public int preIncrement() {
int i = 0;
++i;
return i;
}
public int postIncrement() {
int i = 0;
i++;
return
i;
}
public int negative() {
int i = 0;
i
-= -1;
return
i;
}
public int plusEquals() {
int i = 0;
i
+= 1;
return i;
}
public static void main(String[] args) {
Increment in
= new Increment();
long start
=
System.currentTimeMillis();
for (int i = 0; i < 1000000000;
i++) {
in.preIncrement();
}
System.out.println("preIncrement:"
+
(System.currentTimeMillis() - start));
start =
System.currentTimeMillis();
for (int i = 0; i < 1000000000;
i++) {
in.postIncrement();
}
System.out.println("postIncrement:"
+
(System.currentTimeMillis() - start));
start =
System.currentTimeMillis();
for (int i = 0; i < 1000000000;
i++) {
in.negative();
}
System.out.println("negative:" +
(System.currentTimeMillis() - start));
start =
System.currentTimeMillis();
for (int i = 0; i < 1000000000;
i++) {
in.plusEquals();
}
System.out
.println("plusEquals:" +
(System.currentTimeMillis() - start));
}
}
运行结果,发现四次结果都不一样但是差别极其微小,如图:
但是这样我们是不是就可以说,这四个语句的运行在Java中是有差别或者是无差别的呢?当然不能这样去说,这个程序的具体运行还受限于当前机器的所运行的其他程序以及JVM中的JIT引擎对执行代码的优化等。
其实一个比较合理的办法利用Javap反汇编这个文件,去看看反汇编后各个方法所生成的字节码,由于JVM在运行的时候就是执行这些中间代码,所以比较能够说明问题.
然后我运行javap –c –v
com.jni.test.tracker.object.Increment去反汇编这个代码,得到了preIncrement,postIncrement,negative,plusEquals方法各自的字节码如下:
令人惊讶的是,虽然这四个方法是不一样的,但是经过Java编译器优化后,我们发现生成的四个方法的bytecode实际都是一样的。
下面简单讲解一下这几句bytecode
iconst_0:将int类型的值0压入栈
istore_1: 从栈中弹出int类型值,然后将其存到位置为0的局部变量中
iinc 1,1 : 为局部变量中位置为1的int数 加1
iload_1 : 将局部变量中位置为1的int变量入栈
ireturn : 从栈中弹出int类型值。
public class Increment {
public int preIncrement() {
int i = 0;
++i;
return i;
}
public int postIncrement() {
int i = 0;
i++;
return
i;
}
public int negative() {
int i = 0;
i
-= -1;
return
i;
}
public int plusEquals() {
int i = 0;
i
+= 1;
return i;
}
public static void main(String[] args) {
Increment in
= new Increment();
long start
=
System.currentTimeMillis();
for (int i = 0; i < 1000000000;
i++) {
in.preIncrement();
}
System.out.println("preIncrement:"
+
(System.currentTimeMillis() - start));
start =
System.currentTimeMillis();
for (int i = 0; i < 1000000000;
i++) {
in.postIncrement();
}
System.out.println("postIncrement:"
+
(System.currentTimeMillis() - start));
start =
System.currentTimeMillis();
for (int i = 0; i < 1000000000;
i++) {
in.negative();
}
System.out.println("negative:" +
(System.currentTimeMillis() - start));
start =
System.currentTimeMillis();
for (int i = 0; i < 1000000000;
i++) {
in.plusEquals();
}
System.out
.println("plusEquals:" +
(System.currentTimeMillis() - start));
}
}
运行结果,发现四次结果都不一样但是差别极其微小,如图:
但是这样我们是不是就可以说,这四个语句的运行在Java中是有差别或者是无差别的呢?当然不能这样去说,这个程序的具体运行还受限于当前机器的所运行的其他程序以及JVM中的JIT引擎对执行代码的优化等。
其实一个比较合理的办法利用Javap反汇编这个文件,去看看反汇编后各个方法所生成的字节码,由于JVM在运行的时候就是执行这些中间代码,所以比较能够说明问题.
然后我运行javap –c –v
com.jni.test.tracker.object.Increment去反汇编这个代码,得到了preIncrement,postIncrement,negative,plusEquals方法各自的字节码如下:
public int preIncrement(); Code: Stack=1, Locals=2, Args_size=1 0: iconst_0 1: istore_1 2: iinc 1, 1 5: iload_1 6: ireturn LineNumberTable: line 5: 0 line 6: 2 line 7: 5 LocalVariableTable: Start Length Slot Name Signature 0 7 0 this Lcom/jni/test/tracker/object/Increment; 2 5 1 i I public int postIncrement(); Code: Stack=1, Locals=2, Args_size=1 0: iconst_0 1: istore_1 2: iinc 1, 1 5: iload_1 6: ireturn LineNumberTable: line 11: 0 line 12: 2 line 13: 5 LocalVariableTable: Start Length Slot Name Signature 0 7 0 this Lcom/jni/test/tracker/object/Increment; 2 5 1 i I public int negative(); Code: Stack=1, Locals=2, Args_size=1 0: iconst_0 1: istore_1 2: iinc 1, 1 5: iload_1 6: ireturn LineNumberTable: line 17: 0 line 18: 2 line 19: 5 LocalVariableTable: Start Length Slot Name Signature 0 7 0 this Lcom/jni/test/tracker/object/Increment; 2 5 1 i I public int plusEquals(); Code: Stack=1, Locals=2, Args_size=1 0: iconst_0 1: istore_1 2: iinc 1, 1 5: iload_1 6: ireturn LineNumberTable: line 23: 0 line 25: 2 line 26: 5 LocalVariableTable: Start Length Slot Name Signature 0 7 0 this Lcom/jni/test/tracker/object/Increment; 2 5 1 i I
令人惊讶的是,虽然这四个方法是不一样的,但是经过Java编译器优化后,我们发现生成的四个方法的bytecode实际都是一样的。
下面简单讲解一下这几句bytecode
iconst_0:将int类型的值0压入栈
istore_1: 从栈中弹出int类型值,然后将其存到位置为0的局部变量中
iinc 1,1 : 为局部变量中位置为1的int数 加1
iload_1 : 将局部变量中位置为1的int变量入栈
ireturn : 从栈中弹出int类型值。
相关文章推荐
- Java之深入JVM(1) - 由i++ 和 ++i的执行速度所想到的
- 深入JVM(1): 由i++ 和++i的执行速度所想到的
- [深入理解JVM 一]---Java程序执行流程
- Java之深入JVM(6) - 字节码执行引擎(转)
- 深入理解JVM(二)------Java代码执行机制
- 深入理解JVM(二)------Java代码执行机制
- Java之深入JVM(2) - 由深入JVM(1)想到的一个面试题
- JVM深入学习-Java代码执行篇二-[装载Class ]
- 深入理解JVM(二)------Java代码执行机制
- Java之深入JVM(6) - 字节码执行引擎(转)
- JVM学习笔记(二)------Java代码编译和执行的整个过程
- 深入理解JVM内幕:从基本结构到Java 7新特性
- 深入理解JVM内幕:从基本结构到Java 7新特性
- JVM学习笔记(二)------Java代码编译和执行的整个过程
- java 深入理解JVM--JVM垃圾回收机制
- 深入理解JVM(一)-Java运行时数据区域
- [java]深入理解JVM内存模型
- 深入理解Java虚拟机JVM高级特性与最佳实践阅读总结—— 第七章 虚拟机类加载机制
- 深入Java虚拟机:JVM中的Stack和Heap
- JVM 深入学习:Java 解析 Class 文件过程解析