【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇

文章目录

  • 一、JVM与Java体系结构
    • 1.前言
    • 2.面向人群及参考书目
    • 3.Java及JVM简介
    • 4.Java发展重大事件
    • 5.虚拟机与Java虚拟机
    • 6.JVM整体结构
    • 7.Java代码的执行流程
    • 8.JVM架构模型
    • 9.JVM生命周期
    • 10.JVM发展历程
  • 二、内存结构概述
    • 1.概述类加载器及类加载过程
      • 1.1 类加载过程一:Loading
      • 1.2 类加载过程二:Linking
      • 1.3 类加载过程三:Initialization
    • 2. 类加载器的分类
      • 2.1 引导类加载器Bootstrap ClassLoader
      • 2.2 扩展类加载器Extension ClassLoader
      • 2.3 系统类加载器 AppClassLoader
      • 2.4 例子:自定义一个类加载器
      • 2.5 ClassLoader自定义类加载器的使用及方法
      • 2.6 双亲委派机制的工作原理
      • 2.7 双亲委派机制举例
      • 2.8 沙箱安全机制
  • ==最后得更新==


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体系结构

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第1张图片

1.前言

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第2张图片 【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第3张图片 【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第4张图片

2.面向人群及参考书目

老师在这里提出了几个问题:

  • “栈管运行、堆管存储 ”这句话一定对吗?
  • Java中的堆一定是多线程共享的吗?
  • Java中的对象一定要创建在堆上吗?
  • 方法区中永久带、元空间到底是什么关系?
  • Java为什么叫“半解释型、半编译型”语言?
    【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第5张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第6张图片 【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第7张图片

3.Java及JVM简介

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第8张图片 【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第9张图片 【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第10张图片 【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第11张图片

4.Java发展重大事件

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第12张图片 【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第13张图片 【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第14张图片

5.虚拟机与Java虚拟机

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第15张图片 【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第16张图片 【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第17张图片 【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第18张图片 【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第19张图片

6.JVM整体结构

如下图,其中方法区和堆是多线程共享的,Java栈、本地方法栈、程序计数器是每个线程独有一份的。
执行引擎相当于把字节码文件翻译成机器语言的引擎,使程序可以在操作系统上运行
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第20张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第21张图片

7.Java代码的执行流程

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第22张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第23张图片

8.JVM架构模型

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第24张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第25张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第26张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第27张图片

9.JVM生命周期

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第28张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第29张图片

10.JVM发展历程

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第30张图片

理解执行引擎
解释器的逐行解释特点使得它响应很快,
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第31张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第32张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第33张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第34张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第35张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第36张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第37张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第38张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第39张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第40张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第41张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第42张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第43张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第44张图片

二、内存结构概述

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第45张图片

1.概述类加载器及类加载过程

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第46张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第47张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第48张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第49张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第50张图片

1.1 类加载过程一:Loading

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第51张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第52张图片

1.2 类加载过程二:Linking

在准备阶段:
变量是这个阶段分配值得,但是被final 修饰的static 算是常量了,在编译期就已经分配值了
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第53张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第54张图片

1.3 类加载过程三:Initialization

ps。下图,解释,类变量就是有static修饰的成员变量,所以如果Java程序中没有类变量的显式赋值动作和静态代码块,也没有调用该类的实例的情况,clinit方法是不会出现的
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第55张图片
老师的补充:
clinit 方法相当于类的构造器函数(与类中的静态变量赋值和静态代码块有关)

  • clinit 方法只需要加载一次,加载完以后的类信息就放在方法区(在JDK8的时候叫元空间的一个区域,元空间使用的也就是本地内存,也就是说类加载到内存后给缓存起来了,所以后续使用调用这个类时,加载的都是缓存中的那个类本身,因此clinit也就只需要加载一次就OK了)

init 方法相当于构造器函数。任何一个类在声明以后,内部至少会存在一个类的构造器,(这个构造器可能是你显示声明的,也可能是我们系统默认提供的),它总是会存在的。

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第56张图片

如下图,可以这样把静态变量的声明写在静态代码块的后面,这是因为在“Linking”阶段的“prepare”阶段,默认初始化变量为零值,然后在“Initialization”中顺序执行方法中的静态东东,先是执行静态代码块中给number赋值为20,之后再静态变量赋值时number又变成20
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第57张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第58张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第59张图片

举个栗子:两个线程加载同一个类

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中的语句

执行结果:
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第60张图片

2. 类加载器的分类

前面讲解了,类加载的过程,这节讲述一下有哪几种类加载。

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第61张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第62张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第63张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第64张图片

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

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第65张图片

2.2 扩展类加载器Extension ClassLoader

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第66张图片

2.3 系统类加载器 AppClassLoader

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第67张图片

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 例子:自定义一个类加载器

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第68张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第69张图片

/**
 * 自定义用户类加载器
 * @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;
    }

    public static void main(String[] args) {
        CustomClassLoader customClassLoader = new CustomClassLoader();
        try {
            Class<?> clazz = Class.forName("One",true,customClassLoader);
            Object obj = clazz.newInstance();
            System.out.println(obj.getClass().getClassLoader());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.5 ClassLoader自定义类加载器的使用及方法

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第70张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第71张图片
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第72张图片

由上图可知,扩展类加载器、系统类加载器都是间接的继承自ClassLoader的

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第73张图片

/**
 * 几种不同的方式获取类加载器
 */
public class ClassLoaderTest2 {
    public static void main(String[] args) {
        try {
            //1.
            ClassLoader classLoader = Class.forName("java.lang.String").getClassLoader();
            System.out.println(classLoader);
            //2.
            ClassLoader classLoader1 = Thread.currentThread().getContextClassLoader();
            System.out.println(classLoader1);

            //3.
            ClassLoader classLoader2 = ClassLoader.getSystemClassLoader().getParent();
            System.out.println(classLoader2);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

2.6 双亲委派机制的工作原理

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第74张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第75张图片

解释:双亲委派机制
若自定义了一个类、它所在的包也是自定义的比如com.atguigu.code.Test 加载该类时使用的是AppClassLoader ,但是系统类加载器不会立即加载,而是向上级委托给 Extension ClassLoader,扩展类加载之前讲过是加载 java.etc.dirs 目录下的类,所以不会接受这个委托,于是扩展类加载器继续向上级委托给Bootstrap ClassLoader,引导类加载器是只会加载 java javax sun开头的目录,也不会接受这个委托。

上级都没有一个接受委托的,不帮忙加载这个自定义类,那么这个委托只好向下走最后还回到本身的AppClassLoader,使用系统类加载器加载该类

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第76张图片

2.7 双亲委派机制举例

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第77张图片

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第78张图片

出于安全考虑,禁止自定义的类以java.lang包命名
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第79张图片

2.8 沙箱安全机制

问题:
分析上面的代码和截图,为什么我们自定义shkStart类就会禁止访问java.lang包,而自定义String类就没有报错?
解释:
加载的String类并非我们自定义的String类,而是引导类加载器加载的核心库中的String类。
实质上我们还是不可以自己定义一个类放进java.lang包里面 企图用引导类加载器帮我们加载,这种操作是不安全的也是不允许的,这是出于对类加载器的一种保护机制-----------沙箱安全机制
【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第80张图片




最后得更新

宋红康老师讲解得太详细了,很多人在评论区要PPT,其实对我这样得菜鸟来说理解这些内存啊参数啊什么得枯燥得知识点真的是有难度得!!我都会在老师开始讲解之前按下暂停自己看一遍截图,自己体会一遍,然后再听康老师讲。
结果就是真的康老师讲的会让我更好得理解,比喻也非常得加深印象,让那么多密密麻麻得文字记起来没那么困难。所以一定要听老师去讲一遍,不要只看PPT截图啊!

PPT截图实在太多了,放在一个帖子里也太庞大了。我就花了好几天时间自己在本地做了笔记,导出PDF留着以后自己回顾。

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇_第81张图片

B站评论区有很多人提供PPT截图,想要得去B站看吧。我到这里就不更新啦~
完结撒花~可用了我不少时间呀

你可能感兴趣的:(JVM,jvm,java)