zoukankan      html  css  js  c++  java
  • Java之深入JVM(1) 由i++ 和 ++i的执行速度所想到的

    复制代码
    i++

    ++i

    i
    -=-1

    i
    +=1
    复制代码

    以上的四句代码,问那句的执行速度更快?

    对于C/C++程序员来说,可能首先想到的就是i++和++i要比其他两者要快一些,但是在Java中是不是这样的呢?

    我们可以对他进行一些分析,首先当然想到的是对这些语句利用Java的System.currentTimeMillis()计算单个语句运行很多次(如10亿次)后的时间,然后作比较.

    例如这样:

    测试环境:(1)Windows XP sp3 (2)JDK "1.6.0_07"   Client VM (build 10.0-b23, mixed mode, sharing)


    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));

        }
    }

    运行结果,发现四次结果都不一样但是差别极其微小,如图:

    increment

    但是这样我们是不是就可以说,这四个语句的运行在Java中是有差别或者是无差别的呢?当然不能这样去说,这个程序的具体运行还受限于当前机器的所运行的其他程序以及JVM中的JIT引擎对执行代码的优化等。

    其实一个比较合理的办法利用Javap反汇编这个文件,去看看反汇编后各个方法所生成的字节码,由于JVM在运行的时候就是执行这些中间代码,所以比较能够说明问题.

    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类型值。

     
     
     
  • 相关阅读:
    Uva10305(dfs)
    Uva572
    Uva122
    Uva679
    Uva136
    Uva489
    Uva133
    Uva1339
    Uva1588
    《世纪的哭泣》读后感 读书笔记
  • 原文地址:https://www.cnblogs.com/royi123/p/3132064.html
Copyright © 2011-2022 走看看