`

x=x+1,x+=1,x++效率比较

阅读更多

  最近在做java性能优化的总结,给部门同学分享,在网上看到帖子说到x=x+1,x+=1,x++效率比较,分析了

三种方式的效率,觉得似乎有些道理,一般的结论如下:

 


x=x+1效率最低:
<1>取右x地址
<2>执行x+1得到右值存放到临时变量
<3>取左x地址
<4>将右值传给左x(编译器并不认为左右x地址相同)

其次是x+=1:
<1>取右x地址
<2>执行x+1存放到临时变量
<3>将得到的值传给x(因为x的地址已经读出)

最快的是x++:
<1>取右x地址
<2>x自增1
 于是我把总结的帖子发表了,今天进行demo编写测试发现结果却并非如此:
代码如下:
import java.util.ArrayList;

/**
 * 
* <P>Tiltle: TestXPlus.java </P>
* <P>Description: 测试i=i+1,i+=1,i++的效率 </P>
* @author biyutong
* @date Mar 10, 2012 8:09:52 PM 
* @version:V1.0
 */
public class TestXPlus {

	/** 
	 * <P>Title: main </P>
	 * <P>Description:测试i=i+1,i+=1,i++的效率 </P>
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		long s1 = System.currentTimeMillis();
		Runtime.getRuntime().gc();
		long startMem1 = Runtime.getRuntime().freeMemory();
		System.out.println("开始内存剩余量"+startMem1);
		int x=0;
		for(int i=0;i<2000000000;i++){
			//测试1
			x=x+1;
			//测试2
			//x+=1;
			//测试3
			//x++;
		}
		
		
		
		long s2 = System.currentTimeMillis();
		long startMem2 = Runtime.getRuntime().freeMemory();
		System.out.println("用时: "+(s2-s1)+"毫秒");
		System.out.println("结束时剩余内存: "+startMem2);
		System.out.println("内存使用量: "+(startMem1-startMem2));
		ArrayList<String> test = new  ArrayList<String>();
	}

}
 三个测试结果为:
 写道
//测试1
/*
*开始内存剩余量5036728
*用时: 1450毫秒
*结束时剩余内存: 5018352
*内存使用量: 18376
*/

/*测试2
*开始内存剩余量5036728
*用时: 1450毫秒
*结束时剩余内存: 5018352
*内存使用量: 18376

/*


/*测试3
* 开始内存剩余量5036728
用时: 1449毫秒
结束时剩余内存: 5018352
内存使用量: 18376

*/
 感到有些困惑,后来通过查看论坛上的帖子,觉得可能原因是在java进行编译的时候,最终的指令是一样 的,在运行时就不会有差别了。
  在此,引以为戒,不能盲目看结论,实践出真知。

 

 

3
1
分享到:
评论
6 楼 sd543521 2012-03-11  
canghailan 写道
你这么测试误差太大了。中间有gc(),System.out.println(),这些才是耗时操作。
即使你把时间记录放在循环开始和结束,也是测不准的。
引用

for(int i=0;i<2000000000;i++){  
	//测试1  
	x=x+1;  
	//测试2  
	//x+=1;  
	//测试3  
	//x++;  
}


这个循环的时间才是主要的,你要测试的操作消耗的时间很难测准确。

其实你看一下编译出来的字节码就知道了。
public class Test {
	public static void main(String[] args) {
		int x = 0;
		test1(x);
		test2(x);
		test3(x);
	}
	
	public static int test1(int x) {
		x = x + 1;
		return x;
	}
	
	public static int test2(int x) {
		x += 1;
		return x;
	}
	
	public static int test3(int x) {
		x++;
		return x;
	}
}

javac Test.java
javap -c Test.class
Compiled from "Test.java"
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":
()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_1
       2: iload_1
       3: invokestatic  #2                  // Method test1:(I)I
       6: pop
       7: iload_1
       8: invokestatic  #3                  // Method test2:(I)I
      11: pop
      12: iload_1
      13: invokestatic  #4                  // Method test3:(I)I
      16: pop
      17: return

  public static int test1(int);
    Code:
       0: iload_0
       1: iconst_1
       2: iadd
       3: istore_0
       4: iload_0
       5: ireturn

  public static int test2(int);
    Code:
       0: iinc          0, 1
       3: iload_0
       4: ireturn

  public static int test3(int);
    Code:
       0: iinc          0, 1
       3: iload_0
       4: ireturn
}

可以看出
x = x + 1;
编译后为:
       0: iload_0
       1: iconst_1
       2: iadd
       3: istore_0
x += 1;与x++
编译后为:
       0: iinc          0, 1

其实本来是要这样测试的,但是考虑到后台执行程序会有内存消耗,所以加上了gc,谢谢提醒
5 楼 sd543521 2012-03-11  
canghailan 写道
这三种写法都不会成为系统的性能瓶颈,所有你作优化时不需要考虑这个。反而应该考虑那种写法在上下文中更加清晰,这三种写法的可读性更值得关注。

嗯,是的,从实验来看,基本上没有差别的,以后不会太多考虑这个的。O(∩_∩)O谢谢啦
4 楼 sd543521 2012-03-11  
kanme818 写道
我觉得,在这些上面抠性能还真心不如在流程上抠性能呢,多写一个无用的循环要抠多少个这个啊。
还有就是业务逻辑上抠性能。

是的,目前我们最主要的性能优化还是在db和业务逻辑上,我是在网上看到这个相关的内容进行了测试,之前倒是也没考虑过这个的
3 楼 kanme818 2012-03-11  
我觉得,在这些上面抠性能还真心不如在流程上抠性能呢,多写一个无用的循环要抠多少个这个啊。
还有就是业务逻辑上抠性能。
2 楼 canghailan 2012-03-11  
这三种写法都不会成为系统的性能瓶颈,所有你作优化时不需要考虑这个。反而应该考虑那种写法在上下文中更加清晰,这三种写法的可读性更值得关注。
1 楼 canghailan 2012-03-11  
你这么测试误差太大了。中间有gc(),System.out.println(),这些才是耗时操作。
即使你把时间记录放在循环开始和结束,也是测不准的。
引用

for(int i=0;i<2000000000;i++){  
	//测试1  
	x=x+1;  
	//测试2  
	//x+=1;  
	//测试3  
	//x++;  
}


这个循环的时间才是主要的,你要测试的操作消耗的时间很难测准确。

其实你看一下编译出来的字节码就知道了。
public class Test {
	public static void main(String[] args) {
		int x = 0;
		test1(x);
		test2(x);
		test3(x);
	}
	
	public static int test1(int x) {
		x = x + 1;
		return x;
	}
	
	public static int test2(int x) {
		x += 1;
		return x;
	}
	
	public static int test3(int x) {
		x++;
		return x;
	}
}

javac Test.java
javap -c Test.class
Compiled from "Test.java"
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":
()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_1
       2: iload_1
       3: invokestatic  #2                  // Method test1:(I)I
       6: pop
       7: iload_1
       8: invokestatic  #3                  // Method test2:(I)I
      11: pop
      12: iload_1
      13: invokestatic  #4                  // Method test3:(I)I
      16: pop
      17: return

  public static int test1(int);
    Code:
       0: iload_0
       1: iconst_1
       2: iadd
       3: istore_0
       4: iload_0
       5: ireturn

  public static int test2(int);
    Code:
       0: iinc          0, 1
       3: iload_0
       4: ireturn

  public static int test3(int);
    Code:
       0: iinc          0, 1
       3: iload_0
       4: ireturn
}

可以看出
x = x + 1;
编译后为:
       0: iload_0
       1: iconst_1
       2: iadd
       3: istore_0
x += 1;与x++
编译后为:
       0: iinc          0, 1
Global site tag (gtag.js) - Google Analytics