2, JVM byte code
In front of our own by tomcat jvm parameters and parameters of tomcat optimized, in fact, we want the application to run faster, more efficient, in addition to container and tomcat jvm optimization, the application code itself if efficiency is not written high, it is not enough, therefore, to optimize the program itself also very important.
For optimizing the program itself, you can learn a lot of experience of predecessors, but sometimes, in terms of analysis from the source point of view, it is not good to identify which high efficiency, such as the operation of string concatenation is the direct "+" sign splicing efficiency high or high StringBuilder efficiency?
This time, we need to view the compiled class file byte code, you can find the answer.
We all know that to write applications java, need to pass javac command compiles into class files, and then executed by jvm, jvm execution time is the need to class bytecode file is loaded into the jvm be running.
2.1, view class file byte code command by javap content
First, a simple look Test1 class code:
Check bytecode class files by the contents of the command javap:
See Test1.txt file, as follows:
Classfile /F:/code/itcast‐jvm/itcast‐jvm‐ test/target/classes/cn/itcast/jvm/Test1.class
Last modified 2018‐9‐27; size 577 bytes
MD5 checksum 4214859db3543c0c783ec8a216a4795f Compiled from "Test1.java"
public class cn.itcast.jvm.Test1 minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #5.#23 // java/lang/Object."<init>": ()V
#2 = Fieldref #24.#25 // java/lang/System.out:Ljava/io/PrintStream;
#3 = Methodref #26.#27 // java/io/PrintStream.println: (I)V
#28 = Utf8 cn/itcast/jvm/Test1
#29 = Utf8 java/lang/Object
#30 = Utf8 java/lang/System
#31 = Utf8 out
#32 = Utf8 Ljava/io/PrintStream;
#33 = Utf8 java/io/PrintStream
#34 = Utf8 println
#35 = Utf8 (I)V
{
public cn.itcast.jvm.Test1(); descriptor: ()V
flags: ACC_PUBLIC Code:
stack=1, locals=1, args_size=1 0: aload_0
1: invokespecial #1 // Method
java/lang/Object."<init>":()V
4: return LineNumberTable:
line 3: 0 LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcn/itcast/jvm/Test1;
public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=4, args_size=1 0: iconst_2
1: istore_1
2: iconst_5
3: istore_2
4: iload_2
5: iload_1
6: isub
7: istore_3
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_3
12: invokevirtual #3 // Method
java/io/PrintStream.println:(I)V
15: return LineNumberTable:
line 6: 0
line 7: 2
line 8: 4
line 9: 8
line 10: 15
LocalVariableTable:
Start
0 Length
16 Slot
0 Name
args Signature
[Ljava/lang/String;
2 14 1 a I
4 12 2 b I
8 8 3 c I
}
SourceFile: "Test1.java"
SUMMARY roughly divided into four parts:
Part I: this shows the resulting class java source file, version information, generation time. Part II: shows the class constant pool involved, a total of 35 constants.
Part III: displaying the class constructor, the compiler automatically inserted.
Part IV: displays information about the main parties. (This is the need to focus our attention)
2.2, constant pool
Document official website:
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4-140
2.3 descriptor
2.3.1, field descriptors
官网:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.2
2.3.2、方法描述符
官网:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.3
示例:
The method descriptor for the method:
Object m(int i, double d, Thread t) {...}
is:
(IDLjava/lang/Thread;)Ljava/lang/Object;
2.4、解读方法字节码
public static void main(java.lang.String[]);
descriptor:([Ljava/lang/String;)V //方法描述,V表示该方法的放回值为void
flags:ACC_PUBLIC,ACC_STATIC // 方法修饰符,public、static的
Code:
// stack=2,操作栈的大小为2、locals=4,本地变量表大小,args_size=1, 参数
的个数
stack = 2, locals = 4, args_size = 1
0:iconst_2 //将数字2值压入操作栈,位于栈的最上面
1:istore_1 //从操作栈中弹出一个元素(数字2),放入到本地变量表中,位
于下标为1的位置(下标为0的是this)
2:iconst_5 //将数字5值压入操作栈,位于栈的最上面
3:istore_2 //从操作栈中弹出一个元素(5),放入到本地变量表中,位于第下标为2个位置
4:iload_2 //将本地变量表中下标为2的位置元素压入操作栈(5)
5:iload_1 //将本地变量表中下标为1的位置元素压入操作栈(2)
6:isub //操作栈中的2个数字相减
7:istore_3 // 将相减的结果压入到本地本地变量表中,位于下标为3的位置
// 通过#2号找到对应的常量,即可找到对应的引用
8:getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11:iload_3 //将本地变量表中下标为3的位置元素压入操作栈(3)
// 通过#3号找到对应的常量,即可找到对应的引用,进行方法调用
12:invokevirtual #3 // Method java/io/PrintStream.println:(I)V
15:return //返回
LineNumberTable: //行号的列表
line 6:0
line 7:2
line 8:4
line 9:8
line 10:15 LocalVariableTable: // 本地变量表
Start
0 Length
16 Slot
0 Name
args Signature
[Ljava/lang/String;
2 14 1
a I
4 12 2
b I
8 8 3
c I
}
2.4.1、图解
2.5、研究 i++ 与 ++i 的不同
我们都知道,i++表示,先返回再+1,++i表示,先+1再返回。它的底层是怎么样的呢? 我们一起探究下。
编写测试代码:
2.5.1、查看class字节码
Classfile /F:/code/itcast‐jvm/itcast‐jvm‐ test/target/classes/cn/itcast/jvm/Test2.class
MD5 checksum 901660fc11c43b6daadd0942150960ed Compiled from "Test2.java"
public class cn.itcast.jvm.Test2 minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #8.#27 // java/lang/Object."<init>": ()V
#2 = Class #28 // cn/itcast/jvm/Test2
#3 = Methodref #2.#27 // cn/itcast/jvm/Test2."
<init>":()V
#4 = Methodref #2.#29 // cn/itcast/jvm/Test2.method1: ()V
#5 = Methodref #2.#30 // cn/itcast/jvm/Test2.method2: ()V
#6 = Fieldref #31.#32 // java/lang/System.out:Ljava/io/PrintStream;
#7 = Methodref #33.#34 // java/io/PrintStream.println: (I)V
#26 = Utf8 Test2.java
#27 = NameAndType #9:#10 // "<init>":()V
#28 = Utf8 cn/itcast/jvm/Test2
#29 = NameAndType #20:#10 // method1:()V
#30 = NameAndType #24:#10 // method2:()V
#31 = Class #36 // java/lang/System
#32 = NameAndType #37:#38 // out:Ljava/io/PrintStream;
#33 = Class #39 // java/io/PrintStream
#34 = NameAndType #40:#41 // println:(I)V
#35 = Utf8 java/lang/Object
#36 = Utf8 java/lang/System
#37 = Utf8 out
#38 = Utf8 Ljava/io/PrintStream;
#39 = Utf8 java/io/PrintStream
#40 = Utf8 println
#41 = Utf8 (I)V
{
public cn.itcast.jvm.Test2(); descriptor: ()V
flags: ACC_PUBLIC Code:
stack=1, locals=1, args_size=1 0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return LineNumberTable:
line 3: 0 LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcn/itcast/jvm/Test2;
public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: new #2 // class cn/itcast/jvm/Test2
3: dup
4: invokespecial #3 // Method "<init>":()V
7: invokevirtual #4 // Method method1:()V
10: new #2 // class cn/itcast/jvm/Test2
13: dup
14: invokespecial #3 // Method "<init>":()V
17: invokevirtual #5 // Method method2:()V
20: return LineNumberTable:
line 6: 0
line 7: 10
line 8: 20 LocalVariableTable:
Start Length Slot Name Signature
0 21 0 args [Ljava/lang/String;
public void method1(); descriptor: ()V flags: ACC_PUBLIC Code:
stack=2, locals=3, args_size=1 0: iconst_1
1: istore_1
2: iload_1
3: iinc 1, 1
6: istore_2
7: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_2
11: invokevirtual #7 // Method java/io/PrintStream.println:(I)V
14: return LineNumberTable:
line 11: 0
line 12: 2
line 13: 7
line 14: 14 LocalVariableTable:
Start Length Slot Name Signature
0 15 0 this Lcn/itcast/jvm/Test2; 2 13 1 i I
7 8 2 a I
public void method2(); descriptor: ()V flags: ACC_PUBLIC Code:
stack=2, locals=3, args_size=1 0: iconst_1
1: istore_1
2: iinc 1, 1
5: iload_1
6: istore_2
7: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_2
11: invokevirtual #7 // Method java/io/PrintStream.println:(I)V
14: return LineNumberTable:
line 17: 0
line 18: 2
line 19: 7
line 20: 14 LocalVariableTable:
Start Length Slot Name Signature
0 15 0 this Lcn/itcast/jvm/Test2; 2 13 1 i I
7 8 2 a I
}
SourceFile: "Test2.java"
2.5.2、对比
i++:
++i:
区别:
- i++
只是在本地变量中对数字做了相加,并没有将数据压入到操作栈
将前面拿到的数字1,再次从操作栈中拿到,压入到本地变量中 - ++i
将本地变量中的数字做了相加,并且将数据压入到操作栈
将操作栈中的数据,再次压入到本地变量中
小结:可以通过查看字节码的方式对代码的底层做研究,探究其原理。
2.6、字符串拼接
字符串的拼接在开发过程中使用是非常频繁的,常用的方式有三种:
- +号拼接: str+“456”
- StringBuilder拼接
- StringBuffer拼接
StringBuffer是保证线程安全的,效率是比较低的,我们更多的是使用场景是不会涉及到线程安全的问题的,所以更多的时候会选择StringBuilder,效率会高一些。
那么,问题来了,StringBuilder和“+”号拼接,哪个效率高呢?接下来我们通过字节码的 方式进行探究。
首先,编写个示例:
View Test3.class bytecode
Classfile /F:/code/itcast‐jvm/itcast‐jvm‐ test/target/classes/cn/itcast/jvm/Test3.class
MD5 checksum b3f7629e7e37768b9b5581be01df40d6 Compiled from "Test3.java"
public class cn.itcast.jvm.Test3 minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #14.#36 // java/lang/Object."<init>": ()V
#2 = Class #37 // cn/itcast/jvm/Test3
#3 = Methodref #2.#36 // cn/itcast/jvm/Test3."
<init>":()V
#4 = Methodref #2.#38 // cn/itcast/jvm/Test3.m1:()V
#5 = Methodref #2.#39 // cn/itcast/jvm/Test3.m2:()V
#6 = String #40 // 123
#7 = String #41 // 456
#8 = Class #42 // java/lang/StringBuilder
#9 = Methodref #8.#36 // java/lang/StringBuilder."
<init>":()V
#10 = Methodref #8.#43 // java/lang/StringBuilder.append: (Ljava/lang/String;)Ljava/lang/StringBuilder;
#11 = Methodref #8.#44 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#12 = Fieldref #45.#46 // java/lang/System.out:Ljava/io/PrintStream;
#13 = Methodref #47.#48 // java/io/PrintStream.println: (Ljava/lang/String;)V
#14 = Class #49 // java/lang/Object
#15 = Utf8 <init>
#16 = Utf8 ()V
#17 = Utf8 Code
#18 = Utf8 LineNumberTable
#19 = Utf8 LocalVariableTable
#20 = Utf8 this
#21 = Utf8 Lcn/itcast/jvm/Test3;
#22 = Utf8 main
#23 = Utf8 ([Ljava/lang/String;)V
#24 = Utf8 args
#25 = Utf8 [Ljava/lang/String;
#26 = Utf8 m1
#27 = Utf8 s1
#28 = Utf8 Ljava/lang/String;
#29 = Utf8 s2
#30 = Utf8 s3
#31 = Utf8 m2
#32 = Utf8 sb
#33 = Utf8 Ljava/lang/StringBuilder;
#34 = Utf8 SourceFile
#35 = Utf8 Test3.java
#36 = NameAndType #15:#16 // "<init>":()V
#37 = Utf8 cn/itcast/jvm/Test3
#38 = NameAndType #26:#16 // m1:()V
#39 = NameAndType #31:#16 // m2:()V
#40 = Utf8 123
#41 = Utf8 456
#42 = Utf8 java/lang/StringBuilder
#43 = NameAndType #50:#51 // append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
#44 = NameAndType #52:#53 // toString:
()Ljava/lang/String;
#45 = Class #54 // java/lang/System
#46 = NameAndType #55:#56 // out:Ljava/io/PrintStream;
#47 = Class #57 // java/io/PrintStream
#48 = NameAndType #58:#59 // println:
(Ljava/lang/String;)V
#49 = Utf8 java/lang/Object
#50 = Utf8 append
#51 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#52 = Utf8 toString
#53 = Utf8 ()Ljava/lang/String;
#54 = Utf8 java/lang/System
#55 = Utf8 out
#56 = Utf8 Ljava/io/PrintStream;
#57 = Utf8 java/io/PrintStream
#58 = Utf8 println
#59 = Utf8 (Ljava/lang/String;)V
{
public cn.itcast.jvm.Test3();
descriptor: ()V flags: ACC_PUBLIC Code:
stack=1, locals=1, args_size=1 0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return LineNumberTable:
line 3: 0 LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcn/itcast/jvm/Test3;
public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: new #2 // class cn/itcast/jvm/Test3
3: dup
4: invokespecial #3 // Method "<init>":()V
7: invokevirtual #4 // Method m1:()V
10: new #2 // class cn/itcast/jvm/Test3
13: dup
14: invokespecial #3 // Method "<init>":()V
17: invokevirtual #5 // Method m2:()V
20: return LineNumberTable:
line 6: 0
line 7: 10
line 8: 20 LocalVariableTable:
Start Length Slot Name Signature
0 21 0 args [Ljava/lang/String;
public void m1(); descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=4, args_size=1
0: ldc #6 // String 123
2: astore_1
3: ldc #7 // String 456
5: astore_2
6: new #8 // class
java/lang/StringBuilder 9: dup
10: invokespecial #9 // Method java/lang/StringBuilder."<init>":()V
13: aload_1
14: invokevirtual #10 // Method java/lang/StringBuilder.append: (Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_2
18: invokevirtual #10 // Method java/lang/StringBuilder.append: (Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #11 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore_3
25: getstatic #12 // Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_3
29: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
32: return LineNumberTable:
line 11: 0
line 12: 3
line 13: 6
line 14: 25
line 15: 32 LocalVariableTable:
Start Length Slot Name Signature
0 33 0 this Lcn/itcast/jvm/Test3;
3 30 1 s1 Ljava/lang/String;
6 27 2 s2 Ljava/lang/String;
25 8 3 s3 Ljava/lang/String;
public void m2(); descriptor: ()V flags: ACC_PUBLIC Code:
stack=2, locals=5, args_size=1
0: ldc #6 // String 123
2: astore_1
3: ldc #7 // String 456
5: astore_2
6: new #8 // class java/lang/StringBuilder
9: dup
10: invokespecial #9 // Method java/lang/StringBuilder."<init>":()V
13: astore_3
14: aload_3
15: aload_1
16: invokevirtual #10 // Method java/lang/StringBuilder.append: (Ljava/lang/String;)Ljava/lang/StringBuilder;
19: pop
20: aload_3
21: aload_2
22: invokevirtual #10 // Method java/lang/StringBuilder.append: (Ljava/lang/String;)Ljava/lang/StringBuilder;
25: pop
26: aload_3
27: invokevirtual #11 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
30: astore 4
32: getstatic #12 // Field java/lang/System.out:Ljava/io/PrintStream;
35: aload 4
37: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: return LineNumberTable:
line 18: 0
line 19: 3
line 20: 6
LocalVariableTable
}
SourceFile: "Test3.java"
As can be seen from the de-byte code, M1 () method is to use source code + number splice, but also in the bytecode is compiled into
StringBuilder manner.
Therefore, it can be concluded, string concatenation, + and StringBuilder are equal, the same efficiency. Next, we look at a case:
m1 () and m2 () method in which high efficiency?
Research is still by way of bytecode.
Classfile /F:/code/itcast‐jvm/itcast‐jvm‐ test/target/classes/cn/itcast/jvm/Test4.class
MD5 checksum f87a55446b8b6cd88b6e54bd5edcc9dc Compiled from "Test4.java"
public class cn.itcast.jvm.Test4 minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #14.#39 // java/lang/Object."<init>": ()V
#2 = Class #40 // cn/itcast/jvm/Test4
#3 = Methodref #2.#39 // cn/itcast/jvm/Test4."
<init>":()V
#4 = Methodref #2.#41 // cn/itcast/jvm/Test4.m1:()V
#5 = Methodref #2.#42 // cn/itcast/jvm/Test4.m2:()V
#6 = String #43 //
#7 = Class #44 // java/lang/StringBuilder
#8 = Methodref #7.#39 // java/lang/StringBuilder."
<init>":()V
#9 = Methodref #7.#45 // java/lang/StringBuilder.append: (Ljava/lang/String;)Ljava/lang/StringBuilder;
#10 = Methodref #7.#46 // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
#11 = Methodref #7.#47 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#12 = Fieldref #48.#49 // java/lang/System.out:Ljava/io/PrintStream;
#13 = Methodref #50.#51 // java/io/PrintStream.println: (Ljava/lang/String;)V
#14 = Class #52 // java/lang/Object
#15 = Utf8 <init>
#16 = Utf8 ()V
#17 = Utf8 Code
#18 = Utf8 LineNumberTable
#19 = Utf8 LocalVariableTable
#20 = Utf8 this
#21 = Utf8 Lcn/itcast/jvm/Test4;
#22 = Utf8 main
#23 = Utf8 ([Ljava/lang/String;)V
#24 = Utf8 args
#25 = Utf8 [Ljava/lang/String;
#26 = Utf8 m1
#27 = Utf8 i
#28 = Utf8 I
#29 = Utf8 str
#30 = Utf8 Ljava/lang/String;
#31 = Utf8 StackMapTable
#32 = Class #53 // java/lang/String
#33 = Utf8 m2
#34 = Utf8 sb
#35 = Utf8 Ljava/lang/StringBuilder;
#36 = Class #44 // java/lang/StringBuilder
#37 = Utf8 SourceFile
#38 = Utf8 Test4.java
#39 = NameAndType #15:#16 // "<init>":()V
#40 = Utf8 cn/itcast/jvm/Test4
#41 = NameAndType #26:#16 // m1:()V
#42 = NameAndType #33:#16 // m2:()V
#43 = Utf8
#44 = Utf8 java/lang/StringBuilder
#45 = NameAndType #54:#55 // append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
#46 = NameAndType #54:#56 // append: (I)Ljava/lang/StringBuilder;
#47 = NameAndType #57:#58 // toString:
()Ljava/lang/String;
#48 = Class #59 // java/lang/System
#49 = NameAndType #60:#61 // out:Ljava/io/PrintStream;
#50 = Class #62 // java/io/PrintStream
#51 = NameAndType #63:#64 // println:
(Ljava/lang/String;)V
#52 = Utf8 java/lang/Object
#53 = Utf8 java/lang/String
#54 = Utf8 append
#55 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#56 = Utf8 (I)Ljava/lang/StringBuilder;
#57 = Utf8 toString
#58 = Utf8 ()Ljava/lang/String;
#59 = Utf8 java/lang/System
#60 = Utf8 out
#61 = Utf8 Ljava/io/PrintStream;
#62 = Utf8 java/io/PrintStream
#63 = Utf8 println
#64 = Utf8 (Ljava/lang/String;)V
{
public cn.itcast.jvm.Test4(); descriptor: ()V
flags: ACC_PUBLIC Code:
stack=1, locals=1, args_size=1 0: aload_0
1: invokespecial #1 // Method
java/lang/Object."<init>":()V
4: return LineNumberTable:
line 3: 0 LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcn/itcast/jvm/Test4;
public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: new #2 // class cn/itcast/jvm/Test4
3: dup
4: invokespecial #3 // Method "<init>":()V
7: invokevirtual #4 // Method m1:()V
10: new #2 // class cn/itcast/jvm/Test4
13: dup
14: invokespecial #3 // Method "<init>":()V
17: invokevirtual #5 // Method m2:()V
20: return LineNumberTable:
line 6: 0
line 7: 10
line 8: 20
LocalVariableTable:
Start Length Slot Name Signature
0 21 0 args [Ljava/lang/String;
public void m1(); descriptor: ()V flags: ACC_PUBLIC Code:
stack=2, locals=3, args_size=1
0: ldc #6 // String
2: astore_1 // 将空字符串压入到本地变量表中的下标为1的位置
3: iconst_0 // 将数字0压入操作栈顶
4: istore_2 // 将栈顶数字0压入到本地变量表中的下标为2的位置
5: iload_2 // 将本地变量中下标为2的数字0压入操作栈顶
6: iconst_5 // 将数字5压入操作栈顶
7: if_icmpge 35 //比较栈顶两int型数值大小,当结果大于等于0时跳
转到35
10: new #7 // class
java/lang/StringBuilder
13: dup //复制栈顶数值并将复制值压入栈顶(数字5)
14: invokespecial #8 // Method java/lang/StringBuilder."<init>":()V
17: aload_1
18: invokevirtual #9 // Method java/lang/StringBuilder.append: (Ljava/lang/String;)Ljava/lang/StringBuilder;
21: iload_2 //将本地变量中下标为2的数字0压入操作栈顶
22: invokevirtual #10 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
25: invokevirtual #11 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
28: astore_1
29: iinc 2, 1
32: goto 5
35: getstatic #12 // Field
java/lang/System.out:Ljava/io/PrintStream; 38: aload_1
39: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
42: return LineNumberTable:
line 11: 0
line 12: 3
line 13: 10
line 12: 29
line 15: 35
line 16: 42
LocalVariableTable:
Start Length Slot Name Signature
5 30 2 i I
0 43 0 this Lcn/itcast/jvm/Test4;
3 40 1 str Ljava/lang/String;
StackMapTable: number_of_entries = 2 frame_type = 253 /* append */
offset_delta = 5
locals = [ class java/lang/String, int ] frame_type = 250 /* chop */
offset_delta = 29
public void m2(); descriptor: ()V flags: ACC_PUBLIC Code:
stack=2, locals=3, args_size=1
0: new #7 // class java/lang/StringBuilder
3: dup
4: invokespecial #8 // Method java/lang/StringBuilder."<init>":()V
7: astore_1
8: iconst_0
9: istore_2
10: iload_2
11: iconst_5
12: if_icmpge 27
15: aload_1
16: iload_2
17: invokevirtual #10 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
20: pop
21: iinc 2, 1
24: goto 10
27: getstatic #12 // Field java/lang/System.out:Ljava/io/PrintStream;
30: aload_1
31: invokevirtual #11 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
34: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
37: return LineNumberTable:
line 19: 0
line 20: 8
line 21: 15
line 20: 21
line 23: 27
line 24: 37 LocalVariableTable:
Start Length Slot Name Signature 10 17 2 i I
0 38 0 this Lcn/itcast/jvm/Test4;
8 30 1 sb Ljava/lang/StringBuilder;
StackMapTable: number_of_entries = 2 frame_type = 253 /* append */
offset_delta = 10
locals = [ class java/lang/StringBuilder, int ] frame_type = 250 /* chop */
offset_delta = 16
}
SourceFile: "Test4.java"
You can see, the loop body m1 () method, each cycle will create a StringBuilder object, is less efficient than
m2 () method.
2.7 Summary
Bytecode can be a good way to view the underlying code execution, which can be seen that a high efficiency is achieved, which achieve low efficiency. We can do better optimize our code. Let the program execute more efficiently.