态度决定高度、企图决定版图、格局决定结局

导航

读 Priactical Java 笔记

性能(Performance

 

1.    改善java性能并不是JVM和编译器的单方责任。编写这些程序的程序员也应该尽一份力。

2.    先把焦点放在设计,数据结构和算法本身。

3.    不要倚赖编译期(compile-time)优化技术。

?      看个例子:

?      Java2 SDK javac 相关文档宣称,- o 选项能够为运行期产生优化的代码。

?      class Test

?      {

?             public static void main(String[] args)

?             {

?                    int a = 10 ;

?                    int b = 20 ;

?                    int [] arr = new int[10];

?                    for ( int i = 0 ; i <10 ; i ++ )

?                    {

?                           arr[i] = a + b ;

?                         /*

                                   a+b 这是一个不变量,所以完全可以提出到循环之外,

从而避免每次循环都要进行a+b的计算,但事实,编译器并没有为我们作这个事情。

                            */

                           

?                    }

?                    for ( int i = 0 ; i < 10 ; i ++)

?                    {

?                           System.out.print(i+"\t");              

?                    }

?             }

?      }

       下面让我们看看它生成的bytecod

       javac -o Test.java   // 带优化策略的

       javap -c Test        // 生成bytecod

       ByteCode :

       Compiled from Test.java

       class Test extends java.lang.Object {

           Test();

           public static void main(java.lang.String[]);

       }

      

       Method Test()

          0 aload_0

          1 invokespecial #1 <Method java.lang.Object()>

          4 return

      

       Method void main(java.lang.String[])

          0 bipush 10

          2 istore_1

          3 bipush 20

          5 istore_2

          6 bipush 10

          8 newarray int

         10 astore_3

         11 iconst_0

         12 istore 4

         14 goto 27

         17 aload_3

         18 iload 4

         20 iload_1

         21 iload_2

         22 iadd

         23 iastore

         24 iinc 4 1

         27 iload 4

         29 bipush 10

         31 if_icmplt 17

         34 iconst_0

         35 istore 5

         37 goto 69

         40 getstatic #2 <Field java.io.PrintStream out>

         43 new #3 <Class java.lang.StringBuffer>

         46 dup

         47 invokespecial #4 <Method java.lang.StringBuffer()>

         50 iload 5

         52 invokevirtual #5 <Method java.lang.StringBuffer append(int)>

         55 ldc #6 <String "     ">

         57 invokevirtual #7 <Method java.lang.StringBuffer append(java.lang.String)>

         60 invokevirtual #8 <Method java.lang.String toString()>

         63 invokevirtual #9 <Method void print(java.lang.String)>

         66 iinc 5 1

         69 iload 5

         71 bipush 10

         73 if_icmplt 40

         76 return

注意,[a b 相加]bytecode仍在循环内部(箭头标出的循环结构)。

所以优化并没有任何作用。

4 理解运行期(runtime)代码优化技术

       JIT的目的在于将bytecode于运行期转化成本地二进制码。某些JITS在将bytecode          化之前,对bytecode进行分析并进行优化。

5. 如欲进行字符串接合,StringBuffer优于String

   测试用例:

       public class StringBufferTest

{

       public static void main(String[] args)

       {

              long start = System.currentTimeMillis();

              String str ="chenfei";

             

              for(int i = 0 ; i < 1000; i ++ )

              {

                     str = str + "Hello!" ;             

              }

              long end   = System.currentTimeMillis();

              long t1 = end - start ;

              System.out.println("---------"+t1+"----------"+"\n");

              long start2 = System.currentTimeMillis();

              StringBuffer s = new StringBuffer("chenfei");

             

              for(int j = 0 ; j < 1000; j ++ )

              {

                     s = s.append(" Hello!");

                           

              }

              long end2 = System.currentTimeMillis();

              long t2 = end2 - start2 ;

              System.out.println("----------"+t2+"---------"+"\n");

       }

      

}

结果是:      

---------78----------

 

----------0---------

当循环次数越多,用时差距就越大。

i=j=10000时:

---------18781----------

 

----------16---------

这是为什么呢?让我们看看它的bytecode

Compiled from StringBufferTest.java

public class StringBufferTest extends java.lang.Object {

    public StringBufferTest();

    public static void main(java.lang.String[]);

}

 

Method StringBufferTest()

   0 aload_0

   1 invokespecial #1 <Method java.lang.Object()>

   4 return

 

Method void main(java.lang.String[])

   0 invokestatic #2 <Method long currentTimeMillis()>

   3 lstore_1

   4 ldc #3 <String "chenfei">

   6 astore_3

   7 iconst_0

   8 istore 4

  10 goto 36

  13 new #4 <Class java.lang.StringBuffer>

  16 dup

  17 invokespecial #5 <Method java.lang.StringBuffer()>

  20 aload_3

  21 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>

  24 ldc #7 <String "Hello!">

  26 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>

  29 invokevirtual #8 <Method java.lang.String toString()>

  32 astore_3

  33 iinc 4 1

  36 iload 4

  38 sipush 10000

  41 if_icmplt 13

  44 invokestatic #2 <Method long currentTimeMillis()>

  47 lstore 5

  49 lload 5

  51 lload_1

  52 lsub

  53 lstore 7

  55 getstatic #9 <Field java.io.PrintStream out>

  58 new #4 <Class java.lang.StringBuffer>

  61 dup

  62 invokespecial #5 <Method java.lang.StringBuffer()>

  65 ldc #10 <String "---------">

  67 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>

  70 lload 7

  72 invokevirtual #11 <Method java.lang.StringBuffer append(long)>

  75 ldc #12 <String "----------">

  77 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>

  80 ldc #13 <String "

">

  82 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>

  85 invokevirtual #8 <Method java.lang.String toString()>

  88 invokevirtual #14 <Method void println(java.lang.String)>

  91 invokestatic #2 <Method long currentTimeMillis()>

  94 lstore 9

  96 new #4 <Class java.lang.StringBuffer>

  99 dup

 100 ldc #3 <String "chenfei">

 102 invokespecial #15 <Method java.lang.StringBuffer(java.lang.String)>

 105 astore 11

 107 iconst_0

 108 istore 12

 110 goto 125

 113 aload 11

 115 ldc #16 <String " Hello!">

 117 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>

 120 astore 11

 122 iinc 12 1

 125 iload 12

 127 sipush 10000

 130 if_icmplt 113

 133 invokestatic #2 <Method long currentTimeMillis()>

 136 lstore 13

 138 lload 13

 140 lload 9

 142 lsub

 143 lstore 15

 145 getstatic #9 <Field java.io.PrintStream out>

 148 new #4 <Class java.lang.StringBuffer>

 151 dup

 152 invokespecial #5 <Method java.lang.StringBuffer()>

 155 ldc #12 <String "----------">

 157 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>

 160 lload 15

 162 invokevirtual #11 <Method java.lang.StringBuffer append(long)>

 165 ldc #10 <String "---------">

 167 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>

 170 ldc #13 <String "

">

 172 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>

 175 invokevirtual #8 <Method java.lang.String toString()>

 178 invokevirtual #14 <Method void println(java.lang.String)>

 181 return

如果你愿意看上面的Bytecode,请留意其中加红色的地方,问题的关键。

从其中我们可以知道,在字符串连接的时候,事实是创建了一个新的StringBuffer,然后调用其append方法,而创建实例是很费时的。不能用String相结合的原因在于,String是不可变得,所以只能转换成StringBuffer进行。哈哈,StringBuffer才是你进行字符串结合时的好的选择!

 

       ------待续-----

                                                                                                                -------flyingchen

                                                                                                                -------2005.11.10

 

 

 

 

 

 

 

 

 

 

posted on 2006-01-12 19:28  flyingchen  阅读(469)  评论(0)    收藏  举报