JVM
2021-02-25 18:20:17 6 举报
AI智能生成
java虚拟机学习总结
作者其他创作
大纲/内容
实战
Java 堆溢出
虚拟机栈溢出
本地方法栈溢出
方法区溢出
常量池溢出
本机直接内存溢出
垃圾回收
对象回收的判断
1.引用计数算法
给对象添加一个引用计数器,
每一个地方引用它,计数器值就加1,
对象引用失效的时候,计数器就减1.
计数器值为0的时候,此对象为垃圾
每一个地方引用它,计数器值就加1,
对象引用失效的时候,计数器就减1.
计数器值为0的时候,此对象为垃圾
优点:判定效率高
缺点:对象间循环依赖,此算法
无法正确判断是否为垃圾对象
主流虚拟机没有这种算法
2.可达性分析算法
GC Roots"的对象作为起始点
从这些节点开始向下搜索,
搜索所走过的路径称为引用链(Reference Chain)
当一个对象到GC Roots没有任何引用链相连时,
则证明此对象是不可达的
从这些节点开始向下搜索,
搜索所走过的路径称为引用链(Reference Chain)
当一个对象到GC Roots没有任何引用链相连时,
则证明此对象是不可达的
作为GC Roots对象
栈帧中本地变量表中引用的对象
方法区类静态属性引用的对象
方法区中常量引用的对象
方法栈JNI引用的对象
强引用 Object obj = new Object
软引用 有用非必须
弱引用 非必须
虚引用 最弱的引用
枚举根节点
安全点
安全区域
方法区回收
垃圾回收效率较低
回收内容
废弃常量
无用类
1.该类所有实例都被回收
2.加载该类的ClassLoader被回收
3.该类对应的class对象没有被引用,无法在任何地方反射访问该类方法
垃圾收集算法
标记清除算法(最基础算法)
1.首先标记出所有需要回收的对象
2.在标记完成后统一回收掉所有被标记的对象
缺点1:标记和清除过程的效率都不高
缺点2:产生大量不连续的内存碎片
复制算法
1.内存按容量划分为大小相等的两块
2.一块内存用完了,将存活着的对象复制到另外一块
3.将都是垃圾对象的那块清空内存
缺点1:在对象存活率较高时,复制操作次数多,效率降低
缺点2:內存缩小了一半;需要額外空间做分配担保
标记整理算法
1.标记步骤和标记清除算法相同
2.标记完后垃圾对象移动到一端,然后在清理掉
分代收集算法
新生代
复制算法
老年代
标记-清理或者标记-整理
垃圾收集器
Serial(最基本的收集器)
单线程
垃圾收集的时候,暂停所有线程
优点简单高效,缺点停顿时间长
年轻代-复制算法,老年代-标记整理算法
ParNew收集器
Serial的多线程版本
Parallel Scavenge收集器
新生代收集器
复制算法
吞吐量较高
多线程
Serial Old收集器
Serial的老年代版本
Parallel Old收集器
Parallel的老年代版本
CMS收集器
回收停顿时间短
多线程
标记-清除
1.初始标记 STW
2.并发标记
3.重新标记 STW
4.并发清除
G1收集器
并行并发
分代收集
空间整合
可预测停顿
GC日志
GC日志最前面时间是虚拟机启动以来经过的秒数
【GC 【Full GC 垃圾收集的停顿类型
类加载机制
什么是类的加载机制
类加载的生命周期
加载
1.通过类的全限定名称获取此类的二进制流
2.将这个二进制字节流所代表的静态存储结构转化为方法区的运行时数据结构
3.内存中生成一个java.lang.class对象,作为方法区这个类中各种数据的访问入口
4.可以从ZIP包,网络,动态代理,其他文件比如JSP,数据库等方式
5.加载和连接是交叉进行的
连接
验证
确保Class文件的字节流中包含的信息符合当前虚拟机要求
文件格式验证
元数据验证
字节码验证
符号引用验证
准备
为类变量分配内存并设置类变量初始值
解析
1.类或接口的解析
2.字段解析
3.类方法解析
4.接口方法解析
初始化
执行构造器 <clinit>
收集类中所有类变量的赋值动作和静态语句块中的合并语句
子类的clinit()执行之前,父类clinit()一定执行完成
<clinit>不是必须的,类或者接口中没有对类变量赋值,编译器就可以不生成这个方法
不会执行父接口的(),除非要使用父接口中定义的变量
多线程环境下可以正常加锁,同步,只有一个会去执行,其余挂起,如果有一个线程耗时,那么造成多个线程阻塞
使用
卸载
类加载器
双亲委派模型
启动类加载器(虚拟机中的一部分)
将虚拟机识别的类库加载到内存
其他的类加载器(独立于虚拟机外部)
扩展类加载器
应用程序类加载器
负责加载ClassPath上指定的类库
自定义类加载器
工作过程
1. 防止重复加载同一个.class, 保证数据安全
2. 保证核心.class不能被篡改, 保证了Class执行安全
虚拟机字节码执行引擎
运行时栈帧结构
局部变量表
操作数栈
动态连接
方法返回地址
分派
静态分派
运行时数据区域
程序计数器PCR
1.较小的内存
2.当前线程执行的字节码行号指示器
3.字节码指示器:通过改变这个计数器的值来选取下一条需要执行的指令
4.线程私有
5.如果执行的是java方法,则记录的是字节码指令的地址,如果是Native方法,计数器值为空
6.不会内存溢出
java虚拟机栈
1.线程私有
2.生命周期和线程相同
3.每个方法创建栈帧
1.局部变量表
A.存放编译器可知的各种基本数据类型,对象引用
B.64位的long,dubbo占用两个Slot
C.所需的内存在编译器就确定
2.操作数栈(参数传递池)
算术运算的时候是通过操作数栈来进行的
调用其他方法的时候是通过操作数栈来进行参数传递的
3.动态链接(运行中方法的符号引用的实际指向地址)
保存当前运行方法符号引用的实际指向地址, 指向常量池的类方法地址
解析
1. Class文件在编译过程中,一切方法调用在Class文件里面存储的都只是符号引用
2. 在class文件的加载过程中, 会把符号引用转换为直接引用(方法在实际运行时内存布局中的入口地址)
以上为解析调用的过程, 是静态的, 即在类加载时便清楚对象调用方法的实际指向地址
分派
1. 静态分派--场景:重载--编译过程中根据方法的参数类型确定使用哪个方法的符号引用
2. 动态分派--场景:重写--运行过程中根据对象的实际类型选择使用父类/子类中定义的方法的类方法
4.返回地址
5.异常情况
A:线程请求的栈深度大于虚拟机允许的深度
B:栈拓展内存不够用,内存溢出
本地方法栈
1.线程私有
2.执行的是native方法
3.异常情况和虚拟机栈相同
Java 堆
1.jvm中内存最大的一块
2.线程共享
3.存放对象实例
4.垃圾回收的主要区域
5.新生代
1.Eden
2.From Survivor
3.To Survivor
6.老年代
7.多个线程私有的分配缓存区TLAB
8.物理上不连续的内存空间
9.异常:内存溢出
(永久代)方法区
1.线程共享
2.存储虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码
3.运行时常量池(存储编译器生成的字面量和符号引用)
直接内存
NIO中使用这块内存居多(例如: netty零拷贝)
非堆内存受总内存大小限制
对象的创建
1.new 指令创建对象
A:检查这个指令的参数能否在常量池中找到类的符号引用
B:检查这个符号引用是否已经被加载,解析,初始化过
C:没有的话先进行类加载过程
D:类加载完成后,分配内存
2.分配内存方式
A:指针碰撞
假设内存规整,指针一边是空闲空间一边是被分配空间,通过指针移动表示使用了多少内存
B:空闲列表
C:两种方式取决于垃圾收集器类型,带有压缩整理的垃圾收集器可以使用指针碰撞
D:并发情况下线程不安全
同步
按照线程划分在不同的空间TLAB
E:内存分配好的话将内存空间初始化为0,然后将hashCode,分代年龄等信息保存在对象头
3.对象的内存布局
A:对象头
第一部分存储hashCode,分代年龄,锁信息等数据(MarkWord)
第二部分类型指针(通过这个指针确定是哪个类的实例)
数组的话还存储数据的长度
B:实例数据
类的字段信息,包括父类的字段信息等
存储顺序受分配策略的影响:相同宽度的字段总是被分配到一起
父类中的字段信息在子类之前
C:对齐填充
虚拟机要求对象大小是8字节的整数倍
如果对象大小不是8字节的整数倍的话,需要通过占位符补全
4.对象的访问定位
句柄访问 详看对象访问句柄图 优点:对象移动reference不用修改,句柄池更新即可
直接指针访问 详细看对象指针图 优点:速度块
假设内粗不规整,占用内存后的对象会记录在一张列表上
内存分配策略
年轻代
对象主要分配在新生代的Eden区域
启动本地线程分配缓存的话,则优先在TLAB上分配
优先将对象分配在新生代上, Eden区域内存不够时发送Minor GC
老年代
大对象直接进入老年代
可以配置参数指定大于多大对象直接进入老年代,防止年轻代内存复制频繁
长期存活的对象进入老年代
1.虚拟机给对象添加年龄计数器
2.动态年龄判断
3.空间分配担保
1.Minor GC之前, JVM会判断老年代最大可用的内存是否大于年轻代所有对象内存总和,条件成立那么认为是安全的
2.如果不成立,尝试进行一次Minor GC,这个是有风险的,因为老年代剩余的内存可能不够
3.老年代会判断历史晋升到老年代对象的平均值是否大于老年代剩余的内存, 大于则需要FULL GC 来腾出更多的内存
常用的工具
jps 显示指定系统内所有的虚拟机进程
jstat 监视虚拟机各种运行状态的信息
jinfo 实时查看,调整虚拟机参数
jmap 生成堆转储快照
jhat 虚拟机堆转储快照分析工具
jstack 生成虚拟机当前时刻的线程快照
类文件结构
class文件是一组以8字节为基础单位的二进制流
由无符号数和表构成
0 条评论
下一页