类的加载过程

  1. 加载

    1. 通过一个类的全限定名,获取定义此类的二进制字节流
    2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
    3. 在内存中生成一个代表这个类的java.long.Class对象,作为方法区这个类的各种数据的访问入口
  2. 链接

    1. 验证(Verify):
    2. 目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机自身安全
    3. 主要包括四种验证方式,文件格式验证,元数据验证,字节码验证,符号引用验证
    4. 准备(Prepare):
    5. 为类变量分配内存并且设置该类变量的默认初始值
    6. 这里不包含用final修饰的static(常量),因为final在编译的时候就会分配了,准备阶段会显示的初始化
    7. 这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到java堆中
    8. 解析
  3. 初始化

    1. 初始化阶段就是执行类构造器方法<clinit>()的过程
    2. 此方法不需定义,是javac编译器自动手机类中的所有类变量的赋值动作和静态代码块中的语句合并起来
    3. 构造器方法中指令按语句在源文件中出现的顺序执行

    双亲委派模式

  4. 类的加载

    1. Java虚拟机对class文件采用的是按需加载方式,也就是说当需要使用该类时才会将它的class文件加载到
    2. 内存中生成class对象.而且加载某个类的class文件时,java虚拟机采用的是双亲委派模式,即把请求交由
    3. 给父类处理,他是一种委派模式
  5. 双亲委派机制 ```xml

  6. 如果一个类加载器收到了类加载请求,它并不会自己去加载,而是把这个请求委托给父类的加载器去执行
  7. 如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归请求最终将到达顶层的启动类加载器
  8. 如果父类加载器可以完成加载任务,就返回成功,倘若父类加载器无法完成加载任务,子加载器才会尝试 自己去加载,这就就是双亲委派模型 ``` image.png

  9. 双亲委派模式的优势

    1. 避免类的重复加载
    2. 保护程序安全,防止核心API被随意篡改
  10. 沙箱安全机制

image.png

  1. 在JVM中表示两个class对象是否为同一个类的两个必要条件

    1. 类的完整类名必须一致,包括包名
    2. 加载这个类的ClassLoader(指ClassLoader实例对象)必须相同

    image.png
    灰色为单线程独有的
    红色为多线程共享的

    1. 每个线程:独立包括程序计数器,栈,本地栈
    2. 线程间共享:堆,堆外内存(永久代或元空间,代码缓存 )

    线程

  2. JVM线程

    1. 线程是一个程序里的运行单元.JVM允许一个应用有多个线程并行的执行
    2. 在Hotspot JVM里,每个线程都与操作系统的本地线程直接映射.
    3. 当一个java线程做好执行准备以后,此时一个操作系统的本地线程也同时创建.
    4. 在java线程执行终止后,本地线程也会回收
    5. 操作系统负责所有县城的安排调度到任何一个可用的CPU上,一旦本地线程初始化成功
    6. 他就会调用java线程中的run()方法

    程序计数器(PC寄存器)

  3. 介绍

    1. JVM中的程序计数寄存器
    2. JVM中的PC寄存器是对物理PC寄存器的一种抽象模拟
  4. 作用

    1. PC寄存器用来存储执行下一条指令的地址.也即将要执行的指令代码,由执行引擎去取下一条指令
  5. 两个常见问题 ```xml

  6. 使用PC寄存器存储字节码指令地址有什么用呢? 为什么使用PC寄存器记录当前线程的执行地址呢? 因为CPU需要不停的切换各个线程,这时候切换回来以后,就得知道从哪开始继续执行 JVM的字节码解释器就需要通过改变PC寄存器的值来明确下一条应该执行什么样的字节码指令
  7. PC寄存器为什么被设定为线程私有的 为了能够准确的记录各个线程正在执行的当前字节码指令地址,最好的办法自然是为每一个线程 都分配一个PC寄存器 ```

    虚拟机栈

    垃圾回收器

    image.pngimage.pngimage.pngimage.png
    -XX:+PrintCommandLineFlags : 打印jvm启动的参

垃圾回收中断方式

  1. 抢先式中断

    1. 当垃圾回收发生时,所有线程都中断,没有执行到安全点的,被唤醒继续执行,直到执行到最近的安全点
    2. 现在几乎没有虚拟机采用这种方式
  2. 主动式中断

    1. 当垃圾收集需要中断线程的时候,不对线程直接操作,而是标明一个标志位
    2. 各个线程在执行的时候,不断的去轮询这个标志位,一旦发现标志位为真的时候,在最近的安全点上中断
    3. 轮询标志的地方和安全点是重合的,另外还需要加上创建对象和其他需要在堆上分配内存的时候
    4. 这是为了检查是否即将发生垃圾收集,避免没有足够的内存去分配新的对象

    image.png

    安全区域

  3. 安全点确实解决了如何停顿用户线程的,让虚拟机进入到垃圾回收状态,但是实际情况可能存在一些不同的地方

  4. 比如此时程序是不能继续往下执行的比如用户线程处于Sleep,Blocked状态,这时候当前线程就无法响应虚拟机中断请求
  5. 此时就要引入安全区域了,可以把安全区域理解成扩展和延伸的安全点

    1. 安全区域:
    2. 是指确保在某一段代码片段中, 引用关系不会发生改变
    3. 当用户线程进入安全区域的时候,会标识自己已经进入安全区域了(表明自己在安全区域中),
    4. 那么此时发生垃圾收集,就不用去管这些在安全区域内的线程了,当线程要离开的时候,
    5. 他要检查虚拟机是否完成根节点枚举(或者是垃圾收集期间需要暂停用户线程的阶段),
    6. 如果已经完成了,那就当无事发生,继续执行,如果用户线程还在等待状态,就需要一直等待
    7. 直到收到可以离开安全区域的信号为止

    记忆集与卡表

  6. 记忆集