JIT的比较冷门,首先你要读一下这两篇 帖子:
《面向JIT编程-方法内联》 https://blog.csdn.net/u012834750/article/details/79488572
《浅谈对JIT编译器的理解》 https://www.cnblogs.com/insistence/p/5901457.html
后面就是实战的内容了:
一、我们先看方法内联:
根据帖子里面说的,方法内联只会发生在private方法中,那我们来看一下是不是这样。
public static void main(String[] args) throws ClassNotFoundException {
for (int i = 0; i < 1000000; i++) {
name(i);
}
}
public static void name(int k) {
for (int i = 0; i < k; i++) {
name1(i);
}
}
private static void name1(int i) {
i = i * 100;
}
}
用javac命令编译后,用javap命令查看汇编情况,发现私有函数name1()被内联,我们知道内联最大的好处就是去掉了压栈 弹栈,提升性能。
D:\software\eclipse\eclipse-workspace_solo\TESTTT\src>javap -c Main2
Compiled from "Main2.java"
public class Main2 {
public Main2();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]) throws java.lang.ClassNotFoundException;
Code:
0: iconst_0
1: istore_1
2: iload_1
3: ldc #2 // int 1000000
5: if_icmpge 18
8: iload_1
9: invokestatic #3 // Method name:(I)V
12: iinc 1, 1
15: goto 2
18: return
public static void name(int);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iload_0
4: if_icmpge 17
7: iload_1
8: invokestatic #4 // Method name1:(I)V
11: iinc 1, 1
14: goto 2
17: return
}
二、下面我们来看一下JIT编译:
先看下面代码:
public class Main2 {
public static void main(String[] args) throws ClassNotFoundException {
for (int i = 0; i < 1000000; i++) {
name(i);
}
}
public static void name(int k) {
for (int i = 0; i < k; i++) {
name1(i);
}
}
private static void name1(int i) {
i = i * 100;
}
}
编译后,我们进行运行,但在运行的时候,加上:-XX:+PrintCompilation 参数,这样会把JIT编译的参数打印出来。
D:\software\eclipse\eclipse-workspace_solo\TESTTT\src>java -XX:+PrintCompilation Main2
71 1 3 java.lang.String::hashCode (55 bytes)
72 2 3 java.lang.String::equals (81 bytes)
73 3 4 java.lang.String::charAt (29 bytes)
73 4 3 java.lang.String::<init> (82 bytes)
74 10 4 java.lang.String::length (6 bytes)
74 6 3 java.lang.Character::toLowerCase (9 bytes)
74 11 n 0 java.lang.System::arraycopy (native) (static)
75 7 3 java.lang.CharacterData::of (120 bytes)
75 8 3 java.lang.CharacterDataLatin1::toLowerCase (39 bytes)
76 9 3 java.lang.CharacterDataLatin1::getProperties (11 bytes)
76 5 3 java.util.Arrays::copyOfRange (63 bytes)
80 12 3 java.lang.Object::<init> (1 bytes)
81 13 3 java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes)
82 15 3 java.lang.String::indexOf (70 bytes)
82 17 1 java.lang.Object::<init> (1 bytes)
82 12 3 java.lang.Object::<init> (1 bytes) made not entrant
83 14 3 java.lang.AbstractStringBuilder::append (29 bytes)
84 18 3 java.io.WinNTFileSystem::isSlash (18 bytes)
84 19 s 3 java.lang.StringBuffer::append (13 bytes)
85 16 3 java.lang.StringBuilder::append (8 bytes)
85 20 3 java.lang.AbstractStringBuilder::append (50 bytes)
88 21 3 Main2::name1 (6 bytes)
88 22 3 Main2::name (18 bytes)
88 23 1 Main2::name1 (6 bytes)
89 24 % 4 Main2::name @ 2 (18 bytes)
90 21 3 Main2::name1 (6 bytes) made not entrant
91 25 4 Main2::name (18 bytes)
91 22 3 Main2::name (18 bytes) made not entrant
92 26 % 3 Main2::main @ 2 (19 bytes)
93 27 3 Main2::main (19 bytes)
93 28 % 4 Main2::main @ 2 (19 bytes)
94 26 % 3 Main2::main @ -2 (19 bytes) made not entrant
95 28 % 4 Main2::main @ -2 (19 bytes) made not entrant
通过观察,我们发现name和name1函数都被进行JIT编译了,因为他们都是高热点函数,并且执行次数较多。
那么我们来看一下,如果执行次数比较少的时候,是什么情况呢?我们修改一下代码:
public class Main2 {
public static void main(String[] args) throws ClassNotFoundException {
for (int i = 0; i < 100; i++) { // 这个地方1000000 变成了100
name(i);
}
}
public static void name(int k) {
for (int i = 0; i < k; i++) {
name1(i);
}
}
private static void name1(int i) {
i = i * 100;
}
}
修改后,我们再执行,在看JIT编译函数,你会发现name和name1都不见了,这也验证了JIT是运行时,C1或者C2编译器发现热点函数,进行重新编译起到作用。
D:\software\eclipse\eclipse-workspace_solo\TESTTT\src>java -XX:+PrintCompilation Main2
73 1 3 java.lang.String::hashCode (55 bytes)
74 2 3 java.lang.String::equals (81 bytes)
75 3 4 java.lang.String::charAt (29 bytes)
75 4 3 java.lang.String::<init> (82 bytes)
75 11 n 0 java.lang.System::arraycopy (native) (static)
77 10 4 java.lang.String::length (6 bytes)
77 6 3 java.lang.Character::toLowerCase (9 bytes)
78 7 3 java.lang.CharacterData::of (120 bytes)
78 8 3 java.lang.CharacterDataLatin1::toLowerCase (39 bytes)
79 9 3 java.lang.CharacterDataLatin1::getProperties (11 bytes)
79 5 3 java.util.Arrays::copyOfRange (63 bytes)
83 12 3 java.lang.Object::<init> (1 bytes)
83 13 3 java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes)
84 15 3 java.lang.String::indexOf (70 bytes)
85 18 1 java.lang.Object::<init> (1 bytes)
85 12 3 java.lang.Object::<init> (1 bytes) made not entrant
86 14 3 java.lang.AbstractStringBuilder::append (29 bytes)
87 17 3 java.lang.StringBuilder::append (8 bytes)
88 16 3 java.io.WinNTFileSystem::isSlash (18 bytes)
88 19 s 3 java.lang.StringBuffer::append (13 bytes)
93 20 3 Main2::name1 (6 bytes)