JDK体系架构
JVM体系架构
JDK1.8
Spring Boot程序的JVM参数设置格式(Tomcat启动直接加在bin目录下catalina.sh文件里):
java -Xms2048M -Xmx2048M -Xmn1024M -Xss512K -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -jar app.jar
-Xss
:每个线程的栈大小 (-Xss
设置越小 count 值越小,说明一个线程栈里能分配的栈帧就越少,但是对 JVM 整体来说能开启的线程数会更多);
-Xms
:初始堆大小,默认物理内存的1/64;
-Xmx
:最大堆大小,默认物理内存的1/4;
-Xmn
:新生代大小;
-XX:NewSize
:设置新生代初始大小;
-XX:NewRatio
:默认2表示新生代占年老代的 1/2,占整个堆内存的 1/3;
-XX:SurvivorRatio
:默认 8 表示一个 survivor 区占用 1/8 的 Eden 内存,即 1/10 的新生代内存。
关于元空间的JVM参数有两个:
-XX:MaxMetaspaceSize
: 设置元空间最大值, 默认是 -1, 即不限制, 或者说只受限于本地内存大小;
-XX:MetaspaceSize
: 指定元空间触发 Full GC 的初始阈值(元空间无固定初始大小), 以字节为单位,默认是 21M,达到该值就会触发 Full GC 进行类型卸载, 同时收集器会对该值进行调整: 如果释放了大量的空间, 就适当降低该值; 如果释放了很少的空间, 那么在不超过 -XX:MaxMetaspaceSize
(如果设置了的话) 的情况下, 适当提高该值。这个跟早期 jdk 版本的- XX:PermSize
参数意思不一样,-XX:PermSize
代表永久代的初始容量。
由于调整元空间的大小需要 Full GC,这是非常昂贵的操作,如果应用在启动的时候发生大量 Full GC,通常都是由于永久代或元空间发生了大小调整,基于这种情况,一般建议在JVM参数中将
MetaspaceSize
和MaxMetaspaceSize
设置成一样的值,并设置得比初始值要大,对于 8G 物理内存的机器来说,一般会将这两个值都设置为 256M。
JVM参数汇总查看命令
java -XX:+PrintFlagsInitial //表示打印出所有参数选项的默认值
java -XX:+PrintFlagsFinal //表示打印出所有参数选项在运行程序时生效的值
Class常量池与运行时常量池
Class常量池可以理解为是Class文件中的资源仓库。 Class文件中除了包含类的版本、字段、方法、接口等描述信息外, 还有一项信息就是常量池(constant pool table),用于存放编译期生成的各种字面量(Literal)和符号引用(Symbolic References)。
原java文件如下:
public class Hello1 {
int a = 1;
int b = 2;
String c = "lilei";
public void sayHello(String name){
System.out.println("hello " + name);
}
public static void main(String[] args) {
ClassLoader classLoader = Hello1.class.getClassLoader();
System.out.println(classLoader.getParent().getParent());
System.out.println(classLoader.getParent());
System.out.println(classLoader);
}
}
javap -v Hello1.class
Classfile /Users/admin/IdeaProjects/untitled/out/production/untitled/com/app/Hello1.class
Last modified 2020-7-25; size 1170 bytes
MD5 checksum 31abd4007f2667b26fafdcab763229ca
Compiled from "Hello1.java"
public class com.app.Hello1
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #17.#41 // java/lang/Object."<init>":()V
#2 = Fieldref #13.#42 // com/app/Hello1.a:I
#3 = Fieldref #13.#43 // com/app/Hello1.b:I
#4 = String #44 // lilei
#5 = Fieldref #13.#45 // com/app/Hello1.c:Ljava/lang/String;
#6 = Fieldref #46.#47 // java/lang/System.out:Ljava/io/PrintStream;
#7 = Class #48 // java/lang/StringBuilder
#8 = Methodref #7.#41 // java/lang/StringBuilder."<init>":()V
#9 = String #49 // hello
#10 = Methodref #7.#50 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#11 = Methodref #7.#51 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#12 = Methodref #52.#53 // java/io/PrintStream.println:(Ljava/lang/String;)V
#13 = Class #54 // com/app/Hello1
#14 = Methodref #55.#56 // java/lang/Class.getClassLoader:()Ljava/lang/ClassLoader;
#15 = Methodref #57.#58 // java/lang/ClassLoader.getParent:()Ljava/lang/ClassLoader;
#16 = Methodref #52.#59 // java/io/PrintStream.println:(Ljava/lang/Object;)V
#17 = Class #60 // java/lang/Object
#18 = Utf8 a
#19 = Utf8 I
#20 = Utf8 b
#21 = Utf8 c
#22 = Utf8 Ljava/lang/String;
#23 = Utf8 <init>
#24 = Utf8 ()V
#25 = Utf8 Code
#26 = Utf8 LineNumberTable
#27 = Utf8 LocalVariableTable
#28 = Utf8 this
#29 = Utf8 Lcom/app/Hello1;
#30 = Utf8 sayHello
#31 = Utf8 (Ljava/lang/String;)V
#32 = Utf8 name
#33 = Utf8 main
#34 = Utf8 ([Ljava/lang/String;)V
#35 = Utf8 args
#36 = Utf8 [Ljava/lang/String;
#37 = Utf8 classLoader
#38 = Utf8 Ljava/lang/ClassLoader;
#39 = Utf8 SourceFile
#40 = Utf8 Hello1.java
#41 = NameAndType #23:#24 // "<init>":()V
#42 = NameAndType #18:#19 // a:I
#43 = NameAndType #20:#19 // b:I
#44 = Utf8 lilei
#45 = NameAndType #21:#22 // c:Ljava/lang/String;
#46 = Class #61 // java/lang/System
#47 = NameAndType #62:#63 // out:Ljava/io/PrintStream;
#48 = Utf8 java/lang/StringBuilder
#49 = Utf8 hello
#50 = NameAndType #64:#65 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#51 = NameAndType #66:#67 // toString:()Ljava/lang/String;
#52 = Class #68 // java/io/PrintStream
#53 = NameAndType #69:#31 // println:(Ljava/lang/String;)V
#54 = Utf8 com/app/Hello1
#55 = Class #70 // java/lang/Class
#56 = NameAndType #71:#72 // getClassLoader:()Ljava/lang/ClassLoader;
#57 = Class #73 // java/lang/ClassLoader
#58 = NameAndType #74:#72 // getParent:()Ljava/lang/ClassLoader;
#59 = NameAndType #69:#75 // println:(Ljava/lang/Object;)V
#60 = Utf8 java/lang/Object
#61 = Utf8 java/lang/System
#62 = Utf8 out
#63 = Utf8 Ljava/io/PrintStream;
#64 = Utf8 append
#65 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#66 = Utf8 toString
#67 = Utf8 ()Ljava/lang/String;
#68 = Utf8 java/io/PrintStream
#69 = Utf8 println
#70 = Utf8 java/lang/Class
#71 = Utf8 getClassLoader
#72 = Utf8 ()Ljava/lang/ClassLoader;
#73 = Utf8 java/lang/ClassLoader
#74 = Utf8 getParent
#75 = Utf8 (Ljava/lang/Object;)V
{
int a;
descriptor: I
flags:
int b;
descriptor: I
flags:
java.lang.String c;
descriptor: Ljava/lang/String;
flags:
public com.app.Hello1();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_1
6: putfield #2 // Field a:I
9: aload_0
10: iconst_2
11: putfield #3 // Field b:I
14: aload_0
15: ldc #4 // String lilei
17: putfield #5 // Field c:Ljava/lang/String;
20: return
LineNumberTable:
line 3: 0
line 4: 4
line 5: 9
line 6: 14
LocalVariableTable:
Start Length Slot Name Signature
0 21 0 this Lcom/app/Hello1;
public void sayHello(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
0: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
3: new #7 // class java/lang/StringBuilder
6: dup
7: invokespecial #8 // Method java/lang/StringBuilder."<init>":()V
10: ldc #9 // String hello
12: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: aload_1
16: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #11 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: invokevirtual #12 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: return
LineNumberTable:
line 8: 0
line 9: 25
LocalVariableTable:
Start Length Slot Name Signature
0 26 0 this Lcom/app/Hello1;
0 26 1 name Ljava/lang/String;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: ldc #13 // class com/app/Hello1
2: invokevirtual #14 // Method java/lang/Class.getClassLoader:()Ljava/lang/ClassLoader;
5: astore_1
6: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
9: aload_1
10: invokevirtual #15 // Method java/lang/ClassLoader.getParent:()Ljava/lang/ClassLoader;
13: invokevirtual #15 // Method java/lang/ClassLoader.getParent:()Ljava/lang/ClassLoader;
16: invokevirtual #16 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
19: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
22: aload_1
23: invokevirtual #15 // Method java/lang/ClassLoader.getParent:()Ljava/lang/ClassLoader;
26: invokevirtual #16 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
29: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
32: aload_1
33: invokevirtual #16 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
36: return
LineNumberTable:
line 11: 0
line 12: 6
line 13: 19
line 14: 29
line 15: 36
LocalVariableTable:
Start Length Slot Name Signature
0 37 0 args [Ljava/lang/String;
6 31 1 classLoader Ljava/lang/ClassLoader;
}
SourceFile: "Hello1.java"
字面量就是指由字母、数字等构成的字符串或者数值常量,并且字面量只可以右值出现,所谓右值是指等号右边的值,如:int a=1 这里的a为左值,1为右值。在这个例子中1就是字面量。
符号引用是编译原理中的概念,是相对于直接引用来说的。主要包括了以下三类常量:
- 类和接口的全限定名
- 字段的名称和描述符
- 方法的名称和描述符
上面的a,b,c就是字段名称,就是一种符号引用,还有常量池里的 Lcom/app/Hello1 是类的全限定名,main和sayHello是方法名称,()是一种UTF8格式的描述符,这些都是符号引用。 这些常量池现在是静态信息,只有到运行时被加载到内存后,这些符号才有对应的内存地址信息,这些常量池一旦被装入内存就变成运行时常量池,对应的符号引用在程序加载或运行时会被转变为被加载到内存区域的代码的直接引用,也 就是我们说的动态链接了。例如,sayHello()这个符号引用在运行时就会被转变为sayHello()方法具体代码在内存中的地址,主要通过对象头里的类型指针去转换直接引用。