文章目录
b站视频地址:
https://www.bilibili.com/video/BV1PJ411n7xZ/?p=2
评论区大佬笔记:
https://www.yuque.com/mo_ming/gl7b70/rfot9k
https://www.cnblogs.com/yanl55555/category/1686360.html
一、JVM与Java体系结构
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110149.png#pic_center)
1.前言
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110208.png#pic_center)
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110221.png#pic_center)
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110234.png#pic_center)
2.面向人群及参考书目
老师在这里提出了几个问题:
-
“栈管运行、堆管存储 ”这句话一定对吗?
-
Java中的堆一定是多线程共享的吗?
-
Java中的对象一定要创建在堆上吗?
-
方法区中永久带、元空间到底是什么关系?
-
Java为什么叫“半解释型、半编译型”语言?
-
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110258.png#pic_center)
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110310.png#pic_center)
3.Java及JVM简介
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110320.png#pic_center)
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110330.png#pic_center)
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110339.png#pic_center)
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110351.png#pic_center)
4.Java发展重大事件
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110404.png#pic_center)
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110415.png#pic_center)
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110526.png#pic_center)
5.虚拟机与Java虚拟机
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110536.png#pic_center)
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110544.png#pic_center)
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110552.png#pic_center)
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607110846.png#pic_center)
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607111007.png#pic_center)
6.JVM整体结构
如下图,其中方法区和堆是多线程共享的,Java栈、本地方法栈、程序计数器是每个线程独有一份的。
执行引擎相当于把字节码文件翻译成机器语言的引擎,使程序可以在操作系统上运行
![](https://raw.githubusercontent.com/bluepopo/myblog/master/img/20200607111015.png#pic_center)
7.Java代码的执行流程
8.JVM架构模型
10.JVM发展历程
理解执行引擎
解释器的逐行解释特点使得它响应很快,
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200606102238558.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxODY0NjQ4,size_16,color_FFFFFF,t_70)
二、类加载子系统
1.概述类加载器及类加载过程
1.1 类加载过程一:Loading
1.2 类加载过程二:Linking
在准备阶段:
变量是这个阶段分配值得,但是被final 修饰的static 算是常量了,在编译期就已经分配值了
1.3 类加载过程三:Initialization
ps。下图,解释,类变量就是有static修饰的成员变量,所以如果Java程序中没有类变量的显式赋值动作和静态代码块,也没有调用该类的实例的情况,clinit方法是不会出现的
老师的补充:
clinit 方法
相当于类的构造器函数(与类中的静态变量赋值和静态代码块有关)
- clinit 方法只需要加载一次,加载完以后的类信息就放在方法区(在JDK8的时候叫元空间的一个区域,元空间使用的也就是本地内存,也就是说类加载到内存后给缓存起来了,所以后续使用调用这个类时,加载的都是缓存中的那个类本身,因此clinit也就只需要加载一次就OK了)
init 方法
相当于构造器函数。任何一个类在声明以后,内部至少会存在一个类的构造器,(这个构造器可能是你显示声明的,也可能是我们系统默认提供的),它总是会存在的。
如下图,可以这样把静态变量的声明写在静态代码块的后面,这是因为在“Linking”
阶段的“prepare”
阶段,默认初始化变量为零值,然后在“Initialization”
中顺序执行<clinit>
方法中的静态东东,先是执行静态代码块中给number赋值为20,之后再静态变量赋值时number又变成20
举个栗子:两个线程加载同一个类
package com.atguigu.java;
/**
* @author shkstart
* @create 2020 上午 11:23
*/
public class DeadThreadTest {
public static void main(String[] args) {
Runnable r = () -> {
System.out.println(Thread.currentThread().getName() + "开始");
DeadThread dead = new DeadThread();
System.out.println(Thread.currentThread().getName() + "结束");
};
Thread t1 = new Thread(r,"线程1");
Thread t2 = new Thread(r,"线程2");
t1.start();
t2.start();
}
}
class DeadThread{
static{
if(true){
System.out.println(Thread.currentThread().getName() + "初始化当前类");
while(true){
}
}
}
}
分析上面的代码:
- 验证了一个类只会被加载一次
- DeadThread类一旦类初始化,执行 clinit 方法,就会进入死循环。并且这个类加载初始化只会加载一次的,所以一旦有一个线程去加载该DeadThread类,就出不来了,之后其他线程再也无法加载这个类了。(会处于一种加锁的状态)
- 上面的代码,线程一与线程二只会有一个加载到DeadThread类,打印出static中的语句
执行结果:
2. 类加载器的分类
前面讲解了,类加载的过程,这节讲述一下有哪几种类加载。
public class ClassLoaderTest {
public static void main(String[] args) {
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2
//获取其上层:扩展类加载器
ClassLoader extClassLoader = systemClassLoader.getParent();
System.out.println(extClassLoader);//sun.misc.Launcher$ExtClassLoader@1540e19d
//获取其上层:获取不到引导类加载器
ClassLoader bootstrapClassLoader = extClassLoader.getParent();
System.out.println(bootstrapClassLoader);//null
//对于用户自定义类来说:默认使用系统类加载器进行加载
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2
//String类使用引导类加载器进行加载的。---> Java的核心类库都是使用引导类加载器进行加载的。
ClassLoader classLoader1 = String.class.getClassLoader();
System.out.println(classLoader1);//null
}
}
2.1 引导类加载器Bootstrap ClassLoader
2.2 扩展类加载器Extension ClassLoader
2.3 系统类加载器 AppClassLoader
public class ClassLoaderTest1 {
public static void main(String[] args) {
System.out.println("**********启动类加载器**************");
//获取BootstrapClassLoader能够加载的api的路径
URL[] urLs = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (URL element : urLs) {
System.out.println(element.toExternalForm());
}
//从上面的路径中随意选择一个类,来看看他的类加载器是什么:引导类加载器
ClassLoader classLoader = Provider.class.getClassLoader();
System.out.println(classLoader);
System.out.println("***********扩展类加载器*************");
String extDirs = System.getProperty("java.ext.dirs");
for (String path : extDirs.split(";")) {
System.out.println(path);
}
//从上面的路径中随意选择一个类,来看看他的类加载器是什么:扩展类加载器
ClassLoader classLoader1 = CurveDB.class.getClassLoader();
System.out.println(classLoader1);//sun.misc.Launcher$ExtClassLoader@1540e19d
}
}
2.4 例子:自定义一个类加载器
/**
* 自定义用户类加载器
* @author shkstart
* @create 2019 下午 12:21
*/
public class CustomClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] result = getClassFromCustomPath(name);
if(result == null){
throw new FileNotFoundException();
}else{
return defineClass(name,result,0,result.length);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
throw new ClassNotFoundException(name);
}
private byte[] getClassFromCustomPath(String name){
//从自定义路径中加载指定类:细节略
//如果指定路径的字节码文件进行了加密,则需要在此方法中进行解密操作。
return null;