一、概述
1、知识层次
内存结构、垃圾回收、性能调优
2、内存结构图
上层:入口 class文件+类加载器
编译器javac将java文件编译成字节码class文件
中层:运行时数据区
堆、方法区----共享内存
栈:java栈(虚拟机栈)、本地方法栈----线程私有
程序计数器----线程私有
下层:执行引擎:解释器、编译器(编译后端)、垃圾回收器
二、类加载器---获取类的信息
(一)三个阶段
1、加载阶段
(1) 将class文件字节码加载到内存中,并生成一个这个类的Class对象
(2)作用:.java文件生成.class文件,并在堆中生成一个Class对象
2、链接阶段
(1) 验证---->准备---->解析
- 验证---语法语义问题---编译
- 准备阶段---静态变量分配内存+置0(分配内存+给成员变量赋初始值)
- 解析---将常量池中的符号引用替换为直接引用
符号引用:变量名等字面量
直接引用:物理地址(指向目标的指针或相对偏移量)
(2) static final相关变量在此阶段加载(常量)
3、初始化阶段
开始执行类中编写的代码,进行赋真正的值
(1)主动引用才会发生类的初始化
- 当虚拟机启动,先初始化main方法所在的类
- new一个类的对象
- 使用类的静态成员变量和静态方法(除final常量)
- 通过反射调用类
- 初始化一个类,会先初始化其父类
(2)被动引用不会发生类的初始化
- 通过子类引用父类的静态变量,不会引起子类的初始化
- 通过数组定义类引用,不会触发此类初始化
- 引用常量不会触发此类的初始化(常量在链接阶段就存入类的常量池了)
(二)类加载
1、类加载的作用
将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的数据结构
然后在堆中生成一个代表该类的Class对象,作为方法区中类数据访问入口
2、类加载器的作用
将类装载进内存
3、类加载器分类
(1)启动类加载器---加载java核心类库(JDK)
(2)扩展类加载器---加载核心包之外的jar包
(3)应用程序类加载器---加载class类
4、双亲委派机制
(1)原理:
加载一个对象,首先会一层层委托给各自父类加载器,属于父类加载器加载范畴,则父类加载,否则层层下来,到谁加载谁加载
如,自定义同名String类和核心jar包中String,会通过双亲委派机制,通过引导类加载器加载核心jar包中String
(2)优点
- 避免类的重复加载
- 保护程序安全,防止核心API被恶意攻击---沙箱机制
三、运行时数据区
(一)程序计数器(PC寄存器)
1、作用
存储指向下一条指令的地址
由执行引擎读取下一条指令
2、每个线程一个,内存空间小,运行速度最快
类似数据库结果集的游标或集合的迭代器
3、PC寄存器存储字节码指令地址作用
因为在多线程环境下,cpu需要不停切换给个线程,当切换回来后,就要知道从哪开始继续执行,JVM的字节码解释器需要通过改变PC的寄存器的值来明确下一条应该执行什么样的字节码指令。
(二)栈
1、栈帧
2、局部变量
(三)堆---分代
1、年轻代:eden survivor: s0 +s1(年龄计数器) 8:1:1
(1)每次new对象时,会先放在eden区
(2)当年轻代的Eden区快满时,出发Yong GC,发生STW标记可达对象,是垃圾---清除
(3)将其中存活的对象复制移动到s0或s1区,谁空放在谁那里(to区),
然后遍历标记另一survivor区,垃圾清除,存活则移动到to区(复制算法 )
(4)遍历时,form区的对象被回收超过15次依旧存活时(年龄计数器值=15),就转移到老年区
[注]:
- s0和s1可分为from区和to区
谁空谁是to区,循环调换
- Young GC只有当eden区满的时候才会触发,survivor区满不会触发
2、老年代:年龄值15
老年代空间不足时先触发Major GC----还不足OOM
(四)方法区(元数据区,元空间)
1、堆、栈、方法去的交互关系
2、运行时常量池---方法区中
(1)运行时常量池:方法区的一部分
(2)常量池表:Class文件的一部分,用于存放编译期生成的各种字面量和符号引用
这部分内容在类加载后,存放到方法区的运行时常量池中
3、常量池
(1) 字面量---变量的值---字符串" "或final修饰的常量值
符号引用---变量名(而不是实际的内存地址引用)、
类和接口的全限定名(路径)、
方法的名称和描述符(修饰符、参数)
[注]:
- 全类名:com.sqf.Student
- 全限定名:com/sqf/tudent
- 描述符:字段的数据类型、方法的参数列表、返回值
(2)常量池=常量池计数器+常量池表
常量池计数器---常量池容量
常量池表---存字面量+符号引用---表-----范围[1-常量计数器值-1]
(3)常量池表---用符号的形式表示当前类、方法、变量的相关信息
---根据这些符号可以得到相应的具体的数据类型或参数返回值类型
F float类型
I int类型
J long类型
S short类型
Z boolean类型
V void类型
L 对象类型,如 Ljava/lang/object 表object类型
[ 数组类型 ,如 [[D 表double [ ][ ]
(4)动态链接
符号引用(变量名)-----真正的直接引用(变量地址)
四、执行引擎---逐条解释指令
1、解释器(java.exe):把高级编程语言一行一行直接转译运行
2、编译器(javac.exe):将java源程序编译成中间代码字节码文件
3、垃圾回收器(详见垃圾回收篇)
此部分参考: