Performance optimization -JVM bytecode

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:
Here Insert Picture Description
Check bytecode class files by the contents of the command javap:
Here Insert Picture Description
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
Here Insert Picture Description

2.3 descriptor

2.3.1, field descriptors

官网:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.2
Here Insert Picture Description

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、图解

Here Insert Picture Description

Here Insert Picture Description
Here Insert Picture Description

2.5、研究 i++ 与 ++i 的不同

我们都知道,i++表示,先返回再+1,++i表示,先+1再返回。它的底层是怎么样的呢? 我们一起探究下。

编写测试代码:
Here Insert Picture Description

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++:
Here Insert Picture Description
++i:
Here Insert Picture Description
区别:

  • i++
    只是在本地变量中对数字做了相加,并没有将数据压入到操作栈
    将前面拿到的数字1,再次从操作栈中拿到,压入到本地变量中
  • ++i
    将本地变量中的数字做了相加,并且将数据压入到操作栈
    将操作栈中的数据,再次压入到本地变量中

小结:可以通过查看字节码的方式对代码的底层做研究,探究其原理。

2.6、字符串拼接

字符串的拼接在开发过程中使用是非常频繁的,常用的方式有三种:

  • +号拼接: str+“456”
  • StringBuilder拼接
  • StringBuffer拼接

StringBuffer是保证线程安全的,效率是比较低的,我们更多的是使用场景是不会涉及到线程安全的问题的,所以更多的时候会选择StringBuilder,效率会高一些。

那么,问题来了,StringBuilder和“+”号拼接,哪个效率高呢?接下来我们通过字节码的 方式进行探究。
首先,编写个示例:
Here Insert Picture Description

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:
Here Insert Picture Description

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.

Released 1064 original articles · won praise 888 · views 40000 +

Guess you like

Origin blog.csdn.net/weixin_42528266/article/details/103990663