jvm 类加载的过程, 你学废了吗?
前言 |
我们在编写完成java代码时, 会把java文件编译成class文件, 然后jvm才能执行, 可是jvm是怎么执行这个过程的呢, 如果你还不清楚是怎样的一个加载过程, 相信你看完这篇博客就学废了。
类加载过程 |
类加载过程大概分为5个阶段: 加载, 验证, 准备, 解析, 初始化
加载阶段
这个加载完成了三件事
- 通过类的全限定类名获取类的二进制流
- 将字节流中的静态存储结构转化为方法区的运行时数据结构, 就是把一个静态的变量、类信息等存储起来
- 生成一个java.lang.Class对象, 作为这个类在方法区的访问入口, 这也是反射实现的基础
当然二进制流并非要从哪个class文件中获取, 也可以通过别的途径获取
验证阶段
验证阶段分为 文件格式验证、元数据验证、字节码验证、符号引用验证
-
文件格式验证
是否以魔术0xCAFEBABE开头
主次版本号是否被当前java虚拟机所接受
常量池中的常量类型是否符合规范
指向常量的索引是否指向不存在的常量或者不符合类型的常量
utf-8型的常量中是否有不符合utf-8编码的数据 -
元数据验证
这个类是否有父类(除了object类,其他类的父类都是object)
这个类是否继承了不能够被继承的类
如果不是抽象类, 是否实现了父类或接口中的要求的方法
这个类是否与父类中的字段、方法产生矛盾 -
字节码验证
保证指令代码的正常运行
保证不会跳转到方法以外的字节码指令上
保证类型转换都是正确的 -
符号验证阶段
是否可以通过全限定名找到对应的类
方法字段描述符是否是private、protected、public等的其中一个
方法中引用的类、字段、方法的可访问性是否可以被当前类所访问
准备阶段
准备阶段的工作很简单, 就是为类中定义的变量分配内存并设置类变量初始值的阶段, 但是要注意, 这里只是为类变量分配了初始值, 而不是实例变量
解析
解析就是把符号引用(与虚拟机的内存布局无关)转为直接引用(与虚拟机的内存布局直接相关)
解析主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄、调用点限定符
- 对于类或接口是否引用了其他类或者数组等引用类型, 分别用不同的方式去解析, 最后在验证访问权限
- 对于字段解析确保java虚拟机中字段唯一
- 方法解析确保方法的权限可访问
- 接口方法解析确保接口方法的唯一性, 排除二义性
初始化阶段
这个阶段才是真正开始执行类中编写的ava代码, 初始化类变量和其他资源
总结 |
类加载的过程还是挺复杂的, jvm开发人员想的非常的周到, 确保了虚拟机正常运行不被破坏, 那你学废了吗?