class文件结构 类的加载 执行引擎===》
内存的结构与分配===》
垃圾回收算法与垃圾回收器===》
性能监控(命令行、可视化工具)===》
性能优化
概述
字节码文件的跨平台性:
- java语言是跨平台的语言 write once,run anywhere
- java 虚拟机是跨语言的平台
- JVM 都遵循Java 虚拟机规范
java的前端编译器
javac编译器,前端编译器,idea默认使用javac编译器
AOT编译器:在编译之前字节码文件翻译成机器指令,适用于Linux
透过字节码指令看代码细节
Integer x = 5;
int y = 5;
System.out.println(x == y);//true
valueOf方法源码:
low是-128,high是127
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
intValue 源码:
public int intValue() {
return value;
}
package chapter201;
public class StringTest {
public static void main(String[] args) {
String str = new String("hello") + new String("world");
String str1 = "helloworld";
System.out.println(str == str1);//false
String str2 = new String("helloworld");
System.out.println(str == str2);//false
}
}
package chapter201;
/**
* 成员变量(非静态)的赋值过程:
* 1. 默认初始化
* 2. 显示初始化/代码中初始化
* 3. 构造器中初始化
* 4. 有了对象以后可以对象.属性赋值
*/
class Father{
int x = 10;
public Father() {
this.print();
x = 20;
}
public void print(){
System.out.println("Father.x== " + x);
}
}
class Son extends Father{
int x = 30;
public Son(){
this.print();
x = 40;
}
public void print(){
System.out.println("Son.x= " + x);
}
}
public class SonTest {
public static void main(String[] args) {
Father f = new Son();
System.out.println(f.x);
}
}
虚拟机的基石:Class文件
- 字节码文件是一个二进制的类文件,内容是JVM指令
- 字节码指令:一个字节长度的、代表操作含义的操作码、(所需要的操作数)
- 解读字节码文件:binary-view / notepad安装Hex插件,javap指令,jclasslib
Class文件结构
- Class类本质:Class文件是是一组以8位字节为基础单位的二进制流
- Class文件格式:其中数据项是严格限制的,不允许改变。无符号数和表,u1表示一个字节,u2表示两个字节;表习惯以_info结尾
Class文件结构:
- 魔数
- Class文件版本
- 常量池:存放常量,内容丰富。常量池计数器,常量池表:字面量和符号引用,长度是计数器-1
字面量:
String str = “xinxue”;
final int NUM = 10;
符号引用:
全限定名:com/testJVM/Demo;
描述符:用来描述字段的数据类型
package chapter201;
public class ArrayTest {
public static void main(String[] args) {
Object[] objects = new Object[10];
System.out.println(objects);//对象类型 一维数组 [Ljava.lang.Object;@4554617c
String[] strings = new String[10];
System.out.println(strings);//对象类型 一维数组 [Ljava.lang.String;@74a14482
long[][] longs = new long[10][];
System.out.println(longs);//long类型 二维数组 [[J@1540e19d
}
}
补充:
虚拟机运行时,需要从常量池中获得对应的符号引用,在在类加载过程中的解析阶段将其替换为直接引用,并翻译到具体的内存地址中。
- 符号引用:以一组符号来描述引用的目标
- 直接引用:直接执行目标的指针、相对偏移量或一个能间接定位到目标的句柄。
常量池表:
-
访问标志 access_flag,
两个字节,识别一些类和接口的访问信息
-
类索引,父类索引,接口索引集合
-
字段表集合
字段计数器(两个字节)+字段表
1)用于描述接口或类中声明的变量。字段包含类级变量以及实例级变量;
2)字段叫什么名字、字段被定义为什么类型,需要引用常量池中变量来描述
3)指向常量池索引集合,描述每个字段的完整信息。如字段标识符、访问修饰符、类变量还是实例变量、是否为常量
4)java语言中字段是无法重载的,但是字节码如果两个字段的描述符不一致字段重名就是合法的
5)字段表结构
字段表访问标识
-
方法表集合
指向常量池索引集合,完整描述每个方法的签名。字节码文件中,每一个method_info项都对应着一个类或者接口中的方法信息
-
属性表集合:class文件所携带的辅助信息
字段表、方法表都可以有自己的属性表。
属性计数器+属性表
属性通用格式
字节码具体解析
package chapter201;
public class Demo {
private int num = 1;
public int add(){
num = num + 2;
return num;
}
}
使用javap指令解析Class文件
javac (-g)A.java 编译java文件,有-g参数编译的文件有局部变量表信息
-v不包括私有的信息
javap -v -p A.class 打印包含私有的信息
package chapter201;
public class JavapTest {
private int num;
boolean flag;
protected char gender;
public String info;
public static final int COUNTS = 1;
static {
String url = "www.baidu.com";
}
{
info = "java";
}
public JavapTest() {
}
private JavapTest(boolean flag){
this.flag = flag;
}
private void methodPrivate(){
}
int getNum(int i){
return num + i;
}
protected char showGender(){
return gender;
}
public void showInfo(){
int i = 10;
System.out.println(info + i);
}
}
具体剖析:
Classfile /C:/Users/shen/Desktop/JavapTest.class //字节码文件所属路径
Last modified 2022-3-25; size 1342 bytes //修改时间 字节码文件大小
MD5 checksum 63b66c20420bb17811739794d4ab69a8 // MD5 散列值
Compiled from "JavapTest.java" //源文件名称
public class chapter201.JavapTest
minor version: 0 //副版本
major version: 52 //主版本
flags: ACC_PUBLIC, ACC_SUPER //访问标识
Constant pool: //常量池
#1 = Methodref #16.#46 // java/lang/Object."<init>":()V
#2 = String #47 // java
#3 = Fieldref #15.#48 // chapter201/JavapTest.info:Ljava/lang/String;
#4 = Fieldref #15.#49 // chapter201/JavapTest.flag:Z
#5 = Fieldref #15.#50 // chapter201/JavapTest.num:I
#6 = Fieldref #15.#51 // chapter201/JavapTest.gender:C
#7 = Fieldref #52.#53 // java/lang/System.out:Ljava/io/PrintStream;
#8 = Class #54 // java/lang/StringBuilder
#9 = Methodref #8.#46 // java/lang/StringBuilder."<init>":()V
#10 = Methodref #8.#55 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#11 = Methodref #8.#56 // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
#12 = Methodref #8.#57 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#13 = Methodref #58.#59 // java/io/PrintStream.println:(Ljava/lang/String;)V
#14 = String #60 // www.baidu.com
#15 = Class #61 // chapter201/JavapTest
#16 = Class #62 // java/lang/Object
#17 = Utf8 num
#18 = Utf8 I
#19 = Utf8 flag
#20 = Utf8 Z
#21 = Utf8 gender
#22 = Utf8 C
#23 = Utf8 info
#24 = Utf8 Ljava/lang/String;
#25 = Utf8 COUNTS
#26 = Utf8 ConstantValue
#27 = Integer 1
#28 = Utf8 <init>
#29 = Utf8 ()V
#30 = Utf8 Code
#31 = Utf8 LineNumberTable
#32 = Utf8 LocalVariableTable
#33 = Utf8 this
#34 = Utf8 Lchapter201/JavapTest;
#35 = Utf8 (Z)V
#36 = Utf8 methodPrivate
#37 = Utf8 getNum
#38 = Utf8 (I)I
#39 = Utf8 i
#40 = Utf8 showGender
#41 = Utf8 ()C
#42 = Utf8 showInfo
#43 = Utf8 <clinit>
#44 = Utf8 SourceFile
#45 = Utf8 JavapTest.java
#46 = NameAndType #28:#29 // "<init>":()V
#47 = Utf8 java
#48 = NameAndType #23:#24 // info:Ljava/lang/String;
#49 = NameAndType #19:#20 // flag:Z
#50 = NameAndType #17:#18 // num:I
#51 = NameAndType #21:#22 // gender:C
#52 = Class #63 // java/lang/System
#53 = NameAndType #64:#65 // out:Ljava/io/PrintStream;
#54 = Utf8 java/lang/StringBuilder
#55 = NameAndType #66:#67 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#56 = NameAndType #66:#68 // append:(I)Ljava/lang/StringBuilder;
#57 = NameAndType #69:#70 // toString:()Ljava/lang/String;
#58 = Class #71 // java/io/PrintStream
#59 = NameAndType #72:#73 // println:(Ljava/lang/String;)V
#60 = Utf8 www.baidu.com
#61 = Utf8 chapter201/JavapTest
#62 = Utf8 java/lang/Object
#63 = Utf8 java/lang/System
#64 = Utf8 out
#65 = Utf8 Ljava/io/PrintStream;
#66 = Utf8 append
#67 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#68 = Utf8 (I)Ljava/lang/StringBuilder;
#69 = Utf8 toString
#70 = Utf8 ()Ljava/lang/String;
#71 = Utf8 java/io/PrintStream
#72 = Utf8 println
#73 = Utf8 (Ljava/lang/String;)V
############################字段表集合信息########################################
{
private int num; //字段名
descriptor: I //字段描述符
flags: ACC_PRIVATE //字段访问标识
boolean flag;
descriptor: Z
flags:
protected char gender;
descriptor: C
flags: ACC_PROTECTED
public java.lang.String info;
descriptor: Ljava/lang/String;
flags: ACC_PUBLIC
public static final int COUNTS;
descriptor: I
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
ConstantValue: int 1 //常量字段属性 ConstantValue
#############################方法表集合信息#######################################
public chapter201.JavapTest(); //构造器1的信息
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: ldc #2 // String java
7: putfield #3 // Field info:Ljava/lang/String;
10: return
LineNumberTable:
line 21: 0
line 18: 4
line 23: 10
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 this Lchapter201/JavapTest;
private chapter201.JavapTest(boolean); //构造器2的信息
descriptor: (Z)V
flags: ACC_PRIVATE
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2 // String java
7: putfield #3 // Field info:Ljava/lang/String;
10: aload_0
11: iload_1
12: putfield #4 // Field flag:Z
15: return
LineNumberTable:
line 25: 0
line 18: 4
line 26: 10
line 27: 15
LocalVariableTable:
Start Length Slot Name Signature
0 16 0 this Lchapter201/JavapTest;
0 16 1 flag Z
private void methodPrivate();
descriptor: ()V
flags: ACC_PRIVATE
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 30: 0
LocalVariableTable:
Start Length Slot Name Signature
0 1 0 this Lchapter201/JavapTest;
int getNum(int);
descriptor: (I)I
flags:
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: getfield #5 // Field num:I
4: iload_1
5: iadd
6: ireturn
LineNumberTable:
line 33: 0
LocalVariableTable:
Start Length Slot Name Signature
0 7 0 this Lchapter201/JavapTest;
0 7 1 i I
protected char showGender();
descriptor: ()C
flags: ACC_PROTECTED
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #6 // Field gender:C
4: ireturn
LineNumberTable:
line 37: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lchapter201/JavapTest;
public void showInfo();
descriptor: ()V //方法描述符:方法形参列表、返回值类型
flags: ACC_PUBLIC //方法的访问标识
Code: //方法的Code属性
stack=3, locals=2, args_size=1 //stack:操作数栈深度最大值;locals:局部变量表的长度;args_size:方法接收参数个数
//偏移量:操作码 操作数 指向字符串常量池的索引
0: bipush 10
2: istore_1
3: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
6: new #8 // class java/lang/StringBuilder
9: dup
10: invokespecial #9 // Method java/lang/StringBuilder."<init>":()V
13: aload_0
14: getfield #3 // Field info:Ljava/lang/String;
17: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: iload_1
21: invokevirtual #11 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
24: invokevirtual #12 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: return
//行号表:指明当前字节码指令的便宜来那个与java源程序中代码行号的一一对应关系
LineNumberTable:
line 41: 0
line 42: 3
line 43: 30
//局部变量表:描述内部局部变量的相关信息
LocalVariableTable:
Start Length Slot Name Signature
0 31 0 this Lchapter201/JavapTest;
3 28 1 i I
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=1, locals=1, args_size=0
0: ldc #14 // String www.baidu.com
2: astore_0
3: return
LineNumberTable:
line 13: 0
line 15: 3
LocalVariableTable:
Start Length Slot Name Signature
}
SourceFile: "JavapTest.java" //附加属性:指明当前字节码文件对应的源程序文件名