0
点赞
收藏
分享

微信扫一扫

JVM类加载器

承蒙不弃 2022-04-21 阅读 45
java

一、JVM内存结构

1. 简图

在这里插入图片描述

2. 详图

在这里插入图片描述

二、类加载器简介

1. 基本介绍

  • 类加载器子系统: 只负责从文件系统或网络中加载Class文件,class文件在开头有特定的文件标识
1. ClassLoader只负责class文件的加载,至于是否可以运行,交给Execution Engine决定
2.  加载的类信息,存放在一块称为方法区的内存空间
    2.1 类信息
    2.2 存放运行时常量的信息(字符串字面量和数字常量)

在这里插入图片描述

2. 角色

1. class file  存在于本地硬盘上,可以理解为设计师画在纸上的模版
   最终这个模版在执行的时候,会加载到JVM中,根据模版,创造出n个一摸一样的实例

2. class file 通过二进制流的方式加载到jvm中,被称为DNA元数据模版,放在方法区

3. .class--jvm--元数据模板: 类装载器就是一个快递员的角色

在这里插入图片描述
在这里插入图片描述

三、类加载

1. Loading

1.1 文件来源

  • 从本地文件系统中直接加载
  • 通过网络获取
  • 从zip压缩包中读取,后来转换为jar,war格式
  • 运行时计算生成:动态代理
  • 由其他文件生成:jsp
  • 从加密文件中获取,防止Class文件被反编译的保护,在读取时候需要解密

1.2 Loading过程

1. 通过一个类的全限定类名,获取定义该类的二进制字节流
2. 将这个字节流所代表的静态存储结构转换为方法区的运行时数据结构(元数据)
3. 在堆内存中,生成一个代表该类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
package com.nike.erick.d04;


import java.lang.reflect.Field;

public class ErickService {

    public String name;
    public String address;

    public String getName() {
        return "erick";
    }

    public static void main(String[] args) {

        Class<ErickService> serviceClass = ErickService.class;
        Field[] fields = serviceClass.getFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }
    }
}

2. Linking

2.1 Verify

  • 确保class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机自身安全
  • 文件格式校验,元数据校验,字节码验证,符号引用验证
1. CA FE BA BE: 通过《二进制文件查看器》,发现所有的 .class文件都会以这个开头(魔数)

2.2 Prepare

  • 为类变量分配内存并且设置该类变量的默认初始值,即零值
  • 不包含final修饰的static,因为final在编译的时候就会分配了,准备阶段会显示式初始化
  • 不会为实例变量分配初始化,类变量会分配在方法区中,实例变量会随着对象一起分配到Java堆中

2.3 Resolve

  • 比如一个.class文件,在准备的时候,需要对其父类等也要做一些初始化的准备工作

3. Initialization

3.1 类构造器<clinit>方法

1. 初始化阶段就是: 执行类构造器方法 <clinit>()的过程
  
a. 该方法不需要定义, 是javac编译器自动收集类中的信息,并进行合并
   类变量(static)的赋值动作   静态代码块中的语句

b. 执行顺序:从源文件由上而下

c. 如果不包含上面两种数据,则就不会有clint()

# 因为收集顺序
d. 如果类有父类, JVM保证子类的 <clinit() 在执行前, 父类的 <clinit> 先去执行

# 因为<clint> 是用来加载类变量的,因此只需要加载一次,并在元空间缓存(方法区)
# 类加载天然线程安全
e. 虚拟机保证,一个类的<clinit>()方法在多线程下被同步加锁
  

在IDEA中装  jclasslib来查看
  • 包含<clinit>方法
    在这里插入图片描述
  • 不包含<clinit>方法
    在这里插入图片描述
  • 子父类的<clinit>方法加载顺序
    在这里插入图片描述
  • 多线程下同步加锁
package com.nike.erick.d05;

public class MultiThread {
    public static void main(String[] args) {
        new Thread(() -> {
            Erick erick = new Erick();
        }).start();

        new Thread(() -> {
            Erick erick = new Erick();
        }).start();
    }
}


class Erick {
    static {
        if (true) {
            System.out.println("开始初始化该类");
            while(true){

            }
        }
    }
} 

3.2 类的构造器

1. <clinit>() 和 类的构造器  不是一回事
2. 构造器是虚拟机视角下的  <init>方法
  • 无参构造器

在这里插入图片描述

  • 带参构造器
    在这里插入图片描述
举报

相关推荐

0 条评论