avoid getfield opcode分析

Java String trim() 方法优化
本文探讨了Java中String类的trim()方法实现细节,特别是关于如何通过使用局部变量来减少getfield操作次数,从而提高处理长字符串时的性能。

String 类中trim()方法 有这么一段代码:

Public String trim(){

intlen=value.length;

intst=0;

char[] val = value;/*avoid getfield opcode*/

 

while((st<len)&&(val[st]<='')){

st++;

}

while((st<len)&&(val[len-1]<='')){

len--;

}

return((st>0)||(len<value.length))?substring(st,len):this;

}

 

 

我们看带有注释的一行:

char[] val = value;/*avoid getfield opcode*/

这行有什么意义呢, 直接使用value 不行吗? valuefinal的)

 

下面我们通过opcode层面来看这个问题。

写一个测试类:

 

public class GetfeildTest{

final char[] value=newchar[0];

 

public String test1(){

int len=value.length;

int st=0;

char[]val=value;/*avoidgetfieldopcode*/

 

while((st<len)&&(val[st]<='')){

st++;

}

while((st<len)&&(val[len-1]<='')){

len--;

}

return "test1";

}

 

public Stringtest2(){

int len =value.length;

int st=0;

//char[]val=value;/*avoid get field opcode*/

 

while((st<len)&&(value[st]<='')){

st++;

}

while((st<len)&&(value[len-1]<='')){

len--;

}

return "test2";

}

}

 

可以看到 test1 Stringtrim的方式,而test2while直接使用了value字段。

使用javap -c命令查看操作码:

publicjava.lang.String test1();

    Code:

       0: aload_0

       1: getfield      #2                  // Field value:[C

       4: arraylength

       5: istore_1

       6: iconst_0

       7: istore_2

       8: aload_0

       9: getfield      #2                  // Field value:[C

      12: astore_3

      13: iload_2

      14: iload_1

      15: if_icmpge     32

      18: aload_3

      19: iload_2

      20: caload

      21: bipush        32

      23: if_icmpgt     32

      26: iinc          2, 1

      29: goto          13

      32: iload_2

      33: iload_1

      34: if_icmpge     53

      37: aload_3

      38: iload_1

      39: iconst_1

      40: isub

      41: caload

      42: bipush        32

      44: if_icmpgt     53

      47: iinc          1, -1

      50: goto          32

      53: ldc           #3                  // String test1

      55: areturn


publicjava.lang.String test2();

    Code:

       0: aload_0

       1: getfield      #2                  // Field value:[C

       4: arraylength

       5: istore_1

       6: iconst_0

       7: istore_2

       8: iload_2

       9: iload_1

      10: if_icmpge     30

      13: aload_0

      14: getfield      #2                  // Field value:[C

      17: iload_2

      18: caload

      19: bipush        32

      21: if_icmpgt     30

      24: iinc          2, 1

      27: goto          8

      30: iload_2

      31: iload_1

      32: if_icmpge     54

      35: aload_0

      36: getfield      #2                  // Field value:[C

      39: iload_1

      40: iconst_1

      41: isub

      42: caload

      43: bipush        32

      45: if_icmpgt     54

      48: iinc          1, -1

      51: goto          30

      54: ldc           #4                  // String test2

      56: areturn


我们重点看下第一个goto操作所在行:

Test1

29: goto          13

 

 13: iload_2

 14: iload_1

这个循环里是一些load push和条件判断。

 

test2

  27: goto          8

   8: iload_2

       9: iload_1

      10: if_icmpge     30

      13: aload_0

      14: getfield      #2                  // Field value:[C

      17: iload_2

可以看到这里出现了一个

 14: getfield      #2                  // Field value:[C

getfield操作是一个访问类变量的操作

也就是说如果使用test2 的方式,在while里的每次都会有一个getfield操作,而test1则不会。

通过局部变量的方式,可以避免 getfield 操作,如果value不是一个数组,这其实不会有什么影响。但是如果value数组的长度很大,像String这种可能有超长字符串,就可能会出现一定的性能差异。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值