栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JVM学习笔记(三):类加载

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JVM学习笔记(三):类加载

文章目录
    • 1、类加载阶段(3个)
      • 1.1、加载
      • 1.2、链接
      • 1.3、初始化
    • 2、类加载器
      • 2.1、启动类加载器(Bootstrap)

1、类加载阶段(3个) 1.1、加载

我们都知道,Java类编译成字节码文件后,运行需要通过类加载器,将字节码加载到方法区。
内部采用 C++ 的 instanceKlass 描述 java 类,其中包含field有:

_java_mirror 即 java 的类镜像,例如对 String 来说,就是 String.class,作用是把 klass 暴露给 java 使用
_super 即父类
_fields 即成员变量
_methods 即方法
_constants 即常量池
_class_loader 即类加载器
_vtable 虚方法表
_itable 接口方法表

如果这个类还有父类没有加载,先加载父类
加载和链接可能是交替运行的

注意:

  • instanceKlass 这样的【元数据】是存储在方法区(1.8 后的元空间内),但 _java_mirror是存储在堆中
  • 可以通过前面介绍的 HSDB 工具查看

之前介绍过,类被加载到方法区,由于是JDK1.8,此时方法区实现使用的是元空间,在本地内存中。这样类的字节码都会被加载到元空间当中。
加载的同时,会在堆内存中生成_java_mirror的镜像(Person.class),Person.class持有instanceKlass的内存地址,反之,instanceKlass中的_java_mirror也存有Person.class内存地址。

那么我们通过new关键字创建的实例对象,那么是如何联系起来的?

比如说图中右侧有两个Person实例对象,每个实例对象都有自己的对象头(16个字节),其中8个字节对应着对象的class地址,如果想通过实例对象获取class信息,就会访问对象头,通过class地址先找到_java_mirror(也就是Person.class),再通过类对象Person.class间接的去元空间找到InstanceKlass,这样的话,当我们调用类对象中的getFields()等方法时,实际上是去元空间获取到具体的信息,这就是实例对象、类对象、instanceKlass之间的关系。

1.2、链接

链接阶段可以分为三个小步骤:

  1. 验证:验证字节码是否符合JVM规范,安全性检查
  2. 准备:为 static 变量分配空间,设置默认值


static 变量在 JDK 7 之前存储于 instanceKlass 末尾,从 JDK 7 开始,存储于 _java_mirror(类对象) 末尾
static 变量分配空间和赋值是两个步骤,分配空间在准备阶段完成,赋值在初始化阶段完成
如果 static 变量是 final 的基本类型,以及字符串常量,那么编译阶段值就确定了,赋值在准备阶段完成
如果 static 变量是 final 的,但属于引用类型,那么赋值也会在初始化阶段完成

  1. 解析:将常量池中的符号引用解析为直接引用

解析阶段就是将常量池中的符号引用,解析为直接引用。
符号引用仅仅是个符号,并不知道类、方法、属性到底在哪个内存位置
经过解析之后变成直接引用,就确切知道在内存中的位置

1.3、初始化

初始化即调用 ()V,虚拟机会保证这个类的『构造方法』的线程安全

发生时机:

2、类加载器

接下来介绍类加载器,类加载器是有层级关系的,以JDK8为例:

它们之间还有一种关系:

比如说 Application ClassLoader,它去加载类时,首先会查看一下该类是否被其上级类加载器(Extension ClassLoader)加载过了,如果没有就会再次向上级(Application ClassLoader)询问,如果这两个上级都没有对该类进行加载,自己才会加载该类。
其实,这种类的委托方式,在JVM领域,称之为双亲委派类加载模式

2.1、启动类加载器(Bootstrap)

我们可以通过一些特殊的虚拟机参数,把我们自己编写的类交给启动类加载器进行加载,代码案例如下:

//例如我们自定义一个类:F
public class F {
    static {
        System.out.println("bootstrap F init");
    }
}

=============================================================================

public class Load {
    public static void main(String[] args) throws ClassNotFoundException {
        Class aClass = Class.forName("cn.xu.jvm.load.F");
        System.out.println(aClass.getClassLoader());
    }
}

通过命令行进行代码运行:

//指定启动类加载路径,
java -Xbootclasspath/a:. cn.xu.jvm.load.Load

结果:
bootstrap F init
null  //由于Boostrap ClassLoader不能直接访问,所以这里为null证明就是启动类加载器

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/346074.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号