jvm类加载

一. 问题背景

遇到一道面试题“简述java类加载机制”。今天了解一下类加载。

此笔记仅供自己参考,如有错误请指正

参考:java中级程序员必会的教程,解密JVM【黑马程序员出品】

二. 类的生命周期

类从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期包括:加载验证准备解析初始化使用卸载。其中验证准备解析统称为链接

发生的顺序如下:
在这里插入图片描述

加载、验证、准备、初始化、卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班地开始,而解析阶段则不一定:它在某些情况下可以在初始化阶段之后进行,这是为了支持Java的运行时绑定(即动态绑定 或者 晚期绑定)。这里按部就班地开始,非按部就班地进行 或者 完成。因为这些阶段通常是交叉运行的。通常会在一个阶段中调用或激活另外一个阶段。

三. 类加载的时机

虚拟机规范并没有强行约束类加载的加载阶段什么时候开始,而是由虚拟机自行把握的。但虚拟机规范严格规定初始化阶段有且仅有4种情况必须立即对类进行初始化(而加载、验证、准备自然要在此之前开始)

四. 类加载全过程(有哪些阶段)

我们编译的java代码都是以.java格式文件保存的,而它是不能被jvm执行。jvm需要将.java文件编译成.class文件(即字节码技术),jvm才能真正地执行我们编写的代码。

类加载分为3个大阶段:加载阶段链接阶段初始化阶段。而链接阶段分为:验证阶段准备阶段解析阶段。如下所示:

在这里插入图片描述

4.1 加载阶段

加载阶段是将类的字节码载入方法区中(如果该类的父类还没加载,则先加载父类),其内部采用C++的instanceKlass描述java类,该instanceKlass的重要fields有如下:

  1. _java_mirror即java类的镜像,如String类,就是String.class,作用是把klass暴露给java使用
  2. _super即父类
  3. _fields即成员变量
  4. _methods即成员方法
  5. _constants即常量池
  6. _class_loader即类加载器
  7. _vtable虚方发表
  8. _itable接口方法表

因为klass是采用C++写的,所以java不能直接访问klass,所以就有了java_mirror,其作用是充当了java与c++的桥梁,使得java通过java_mirror能访问到klass。

如下图:
在这里插入图片描述
注:instanceKlass的元数据是存储在方法区内(即jdk1.8的元空间),而java_mirror是存储在堆中的。

4.2 链接阶段

链接阶段分为3个:验证阶段准备阶段解析阶段

4.2.1 验证阶段

验证加载进来的类(实际上指字节码)是否符合jvm规范,这是一个安全性检查。

加入修改了类的字节码,比如它的魔数,运行的时候将会报出ClassFormatError,如下:
在这里插入图片描述

4.2.2 准备阶段

准备阶段是为static变量分配空间,设置默认值。

内容有:

  • static变量jdk1.7以前存储与instanceKlass的末尾,而jdk1.7及以后则存于java_mirror末尾(因为java_mirror在jdk1.7及以后是存储在堆中的,所以static变量也是存于堆中

  • static变量分配空间和赋值是2个步骤:分配空间是在准备阶段完成的;赋值是在初始化阶段完成的

  • 如果static变量是final的基本数据类型 以及 字符串常量,那么编译阶段值就确定了,所以赋值在准备阶段完成

  • 如果static变量是final的引用类型,那么赋值在初始化阶段完成

如下:
在这里插入图片描述
在这里插入图片描述

4.2.3 解析阶段

将常量池的符号引用解析为直接引用(即将符号引用改为内存地址,直接去内存地址查找)

如下:
在这里插入图片描述
在这里插入图片描述

4.3 初始化阶段

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

类初始化是懒惰的,即当jvm用的某个类,才会去加载那个类。

4.3.1 导致类初始化的情况

  1. main方法所在的类,总会被首先初始化

  2. new会导致初始化

  3. 首次访问类的静态变量或静态方法时

  4. 子类初始化,如果父类还未初始化,则先初始化父类

  5. 子类访问父类的静态变量,只初始化父类

  6. Class.forName触发初始化

4.3.2 不导致类初始化的情况

  1. 访问该类的static final静态常量(即基本数据类型 以及 字符串常量),因为它们的值在编译阶段就确定,然后static final变量在准备阶段会完成分配空间 以及 赋值 ,所以不会触发初始化

  2. 类对象.class不会触发初始化(因为类对象.class是在类加载阶段完成的,即字节码)

  3. 类加载器的loadClass方法

  4. Class.forName的参数2为false时

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值