JVM调优实战:三、Class文件是如何被加载到JVM的?

Class文件是如何被加载到JVM的?

前面我们讲了class的文件结构,相信大家对class文件的构成以及他们之间的排列顺序都有了比较深的了解。说一个小伙伴可能会问的问题,了解学习class文件结构有什么用?工作也用不上它,我们也没有达到发明一门语言的高度,还没法创造一门语言,然后将这门语言变成class文件丢到JVM上运行。
这个其实就像你学习古诗词一样,你说学习古诗词有什么用?至少能提高你的审美以及文化水平吧,那么了解class文件结构,起码能让你更加了解底层代码的运行原理,提高技术的认知水平,而且你在简历上加上了解class的文件结构,那么你的简历就跟别人区分开来了。

JVM加载class文件的三大步骤

加载阶段(Loading)、连接阶段(Linking)、初始化阶段(Initializing)

加载阶段(Loading)

加载阶段主要做以下3件事情:

  1. 通过类全限定名获取定义此类的二进制字节流;
  2. 将字节流代表的静态存储结构转换为方法区的运行时数据结构;
  3. 在内存中生成此类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
    在加载阶段我们探讨两个问题,如何触发JVM加载class文件?获取类的二进制字节流的方式有哪些?

如何触发JVM加载class文件?

  • 遇到new、getstatic、putstatic或者invokestatic字节码指令的时候,如果类还没有初始化
  • 使用java.lang.reflect包的方法对类进行反射的时候,如果类还没有初始化
  • 初始化类的时候,如果父类还没有初始化,则触发父类初始化
  • 虚拟机器启动时,main方法所在的类会首先进行初始化
  • JDK1.7中使用动态语言支持的时候,如果一个java.lang.invoke.MethodHandler实例最后解析为:REF_getStatic,REF_putStatic,REF_invokeStatic方法句柄的时候,并且句柄所对应的类没有进行过初始化

获取类的二进制字节流的方式有哪些?

  • zip包,延伸为JAR、EAR、WAR包
  • 网络,如Applet
  • 动态代理
  • JSP生成
  • 数据库获取
    另外在加载阶段也会对class做一些基础的验证,但这里的验证不是连接阶段的验证。

连接阶段(Linking)

Linking阶段又分为三小步,分别是:

1. Verification:这步叫验证,验证class文件是否符合jvm规定,格式不对就不会进行下一步。

验证的内容及步骤:

元数据验证

主要是语义校验,保证不存在不符合Java语言规范的元数据信息,如:没有父类,继承了final类,接口的非抽象类实现没有完整实现方法等。

字节码验证

主要对数据流和控制流进行分析,确定成行语义是否合法,符合逻辑。
不合法的例子:
操作数栈放置了int类型数据,却当成long类型使用;
把父类对象赋值给了子类数据类型;

符号引用验证

解析阶段发生的验证,当把符号引用转化为直接引用的时候进行验证。这主要是对类自身以外的信息进行匹配性校验。
主要包括:

  • 全限定名是否可以找到对应的类;
  • 指定类是否存在符合方法的字段描述符以及简单名称所描述的方法和字段;
  • 校验类,字段和方法的可见性;

2. Preparation:这步叫准备,给静态成员变量赋默认值。

3. Resolution:这步叫解析,将类、方法、属性等等符号引用解析为直接引用,将常量池中的各种符号引用解析为指针、偏移量等内存地址的直接引用。

符号引用:字面量,引用目标不一定已经加载到内存中;
直接引用:直接指向目标的指针,或者相对偏移量,或是一个能简介定位到目标的句柄。直接引用和虚拟机实现的内存布局相关。
解析主要针对以下七类符号引用进行:

  • 类或接口 CONSTANT_Class_info
  • 字段 CONSTANT_Fieldref_info
  • 类方法 CONSTANT_Methodref_info
  • 接口方法 CONSTANT_InterfaceMethodref_info
  • 方法类型 CONSTANT_MethodType_info
  • 方法句柄 CONSTANT_MethodHandle_info
  • 调用限定符 CONSTANT_InvokeDynamic_info

初始化阶段(Initializing)

这一步主要是对类的静态变量初始化为指定的值,执行静态代码块。
比如代码 public static final int a = 12; 在准备阶段就给给static变量赋了默认值,也就是0,这一步就把12赋值给它。
还有 static的 User public static User user = new User(); 实例化User

Seven的代码实验室,示例代码仓库

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Seven的代码实验室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值