一、初识JVM
二、字节码文件详解
(一)、JVM的组成
(二)、字节码文件的组成
1、基本信息
JDK8及以后,主版本号-44=JDK版本
2、常量池
3、方法
(三)、类的生命周期
1、概述
2、加载阶段
3、连接阶段
(1)、验证阶段
(2)、准备阶段
注意特例:
(3)、解析阶段
4、初始化阶段
(1)、概述
(2)、练习一
先初始化main方法所在的类,打印D,在打印A,创建对象时先执行构造代码块,打印C,执行构造方法打印B,打印CB
(3)、练习二
创建父类,子类不会初始化
创建子类,父类会初始化
(4)、练习三
(四)、类加载器
1、JDK8及以前类加载器的分类
(1)、启动类加载器
(2)、扩展类加载器
(3)、应用程序类加载器的
2、双亲委派机制
3、打破双亲委派机制
(1)、自定义类加载器
loadClass双亲委派机制源码
Class loadClass{
//双亲委派机制部分代码
Class findClass{
//根据路径获取字节码二进制文件
Class defineClass{
//对字节码二进制文件进行校验
//将二进制文件加载到方法区和栈中
}
}
}
打破双亲委派机制:
自定义类加载器,重写loadClass()方法,删除双亲委派机制部分代码,直接加载二进制文件,然后调用defineClass()方法
如果自定义类加载器而不想破坏双亲委派机制,应该重写findClass()方法
(2)、线程上下文类加载器
SPI机制
(3)、Osgi框架的类加载器
4、JDK9以后的类加载器
5、总结
三、JVM的内存取区域(运行时数据区)
(一)、程序计数器
(二)、栈
1、虚拟机栈
2、栈帧组成
(1)、局部变量表
(2)、操作数栈
(3)、帧数据
动态链接
方法出口
异常表的引用
3、虚拟机栈内存溢出
(三)、堆(线程之间共享)
(四)、方法区(共享)
1、类的元信息
2、运行时常量池
3、字符串常量池
false
true
JDK6中
JDK8(7及以后)中
(五)、直接内存(共享)
(六)、总结
四、垃圾回收
(一)、方法区的回收
我们平时所写的代码都是由应用程序类加载器加载的,应用程序类加载器不会被回收所以我们写的类不会被回收
(二)、堆回收
1、引用计数法和可达性分析法
(1)、引用计数法
(2)、可达性分析法
- 线程Thread对象。
- 系统类加载器加载的java.lang.Class对象。(一般关联着静态变量)
- 监视器对象,用来保存同步锁synchronized关键字持有的对象。
- 本地方法调用时使用的全局对象。
2、五种对象引用
(1)、强引用
(2)、软引用
软引用对象设计
在每次放入hashmap中时,对队列进行遍历删除,hashmap根据软引用对象中的key删除相应的key和value
(3)、弱引用
用法和软引用相似
(4)、虚引用
(5)、终结器引用
3、垃圾回收算法
(1)、标记清除算法
(2)、复制算法
(3)、标记整理算法
(4)、分代GC
minor GC用的是复制算法
不一定是年龄到达15的时候才能进入老年代,如果年轻代已经满了,年轻代的对象会提前进入老年代,所以要先进行mirror GC,失败再进行Full GC
4、垃圾回收器
(1)、年轻代-Serial
Serial和SerialOld适用于CPU资源匮乏的情况下,都是单线程回收
(2)、老年代-SerialOld
Serial和SerialOld适用于CPU资源匮乏的情况下
(3)、年轻代-ParNew
多线程回收
(4)、老年代- CMS(Concurrent Mark Sweep)垃圾回收器
尽量减少STW时间
(5)、年轻代-Parallel Scavenge
可以设置吞吐量和最大暂停时间
![](https://i-blog.csdnimg.cn/blog_migrate/c6e01de6a8dec5e7c060d05381f914e0.png)
(6)、老年代-Parallel Old
(7)、G1
g1回收器总堆占有率到45%时会触发MixedGc,但年轻代需要到达60%才会触发youngGC,那岂不是每次到达45%时就直接触发MixedGC了吗?
MixedGC有两种方式触发,一种是大对象直接入h,另一种走晋升。如果是走晋升,youngGC是MixedGC的前置,也就是g1应该优先younggc,毕竟mixedgc中的并发标记是依赖于younggc作初始标记的。younggc之后,正常系统绝大多数对象会被回收掉,满足晋升条件的对象晋升到老年代,这个时候才会去检测45%这个阈值,那很有可能由于youngc的对象释放,这个阈值已经不满足条件了。