博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JVM类加载原理学习笔记
阅读量:4984 次
发布时间:2019-06-12

本文共 1300 字,大约阅读时间需要 4 分钟。

(1)类的生命周期包括了:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸载(Unloading)七个阶段

(2)当Java程序需要使用某个类时,JVM会确保这个类已经被加载、连接(验证、准备和解析)和初始化。

(3)加载阶段:通过一个类的全限定名来获取此类的二进制字节流;将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;在java堆中生成一个代表这个类的Class对象,作为方法区这些数据的访问入口;

(4)验证阶段:验证是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全;包括文件格式验证、元数据验证、字节码验证、符号引用验证;如果验证到输入的字节流不符合Class文件的存储格式,就抛出一个java.lang.VerifyError异常或其子类异常。

(5)准备阶段:准备阶段是正式为类变量分配内存并设置类变量初始值(各数据类型的零值)的阶段,这些内存将在方法区中进行分配。

(6) 解析阶段:解析阶段是在虚拟机将常量池内的符号引用替换为直接引用的过程。符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。符号引用与虚拟机实现的内存布局无关,引用的目标并不一定已经加载到内存中。直接引用:直接引用可以是直接指向目标的指针、相对偏移量或者一个能间接定位到目标的句柄。如果有了直接引用,那引用的目标必定已经在内存中存在。

(7)初始化阶段:初始化阶段是执行类构造器<clinit>()方法的过程。

初始化是重点,需要清楚以下几点

1、<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序决定的。静态语句块只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块中可以赋值,但是不能访问。

2、 方法与实例构造器<cinit>()不同,不需要显示的调用父类构造器,虚拟机会保证在子类的<clinit>()方法执行之前,父类的<clinit>()已经执行完毕。

3、<clinit>()方法对于类或接口来说不是必须的,如果一个类中没有静态语句块也没有对变量的赋值操作,那么编译器可以不为这个类生成<clinit>()方法。

4、 执行接口的<clinit>()不需要先执行父接口的<clinit>()方法,只有当父接口中定义的变量被使用时,父接口才会被初始化。接口的实现类在初始化时也不会执行接口的<clinit>()方法。

5、虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确的加锁和同步,如果多个线程同时去初始化一个类,则只会有一个线程去执行这个类的<clinit>()方法,其他线程需要阻塞等待。

转载于:https://www.cnblogs.com/aiwz/p/6154529.html

你可能感兴趣的文章
Struts2+Hibernate+Spring+Webservice 项目从Tomcat到WebLogic遇到问题的解决方法
查看>>
C# 代理/委托 Delegate
查看>>
笨方法学python--参数,解包,变量
查看>>
android 加载本地图片与网络图片
查看>>
易经读书笔记17 泽雷随
查看>>
oracle正则表达式函数 匹配
查看>>
jmeter --自动化badboy脚本开发技术
查看>>
Linux驱动:LCD驱动测试
查看>>
Mark Down 尝试
查看>>
第三节:使用Log4net和过滤器记录异常信息,返回异常给前端
查看>>
fedora的选择
查看>>
AlphaPose论文笔记《RMPE: Regional Multi-person Pose Estimation》
查看>>
模糊查询和聚合函数
查看>>
[批处理]批量将文件名更名为其上级目录名
查看>>
如何查找ORACLE中的跟踪文件
查看>>
SQL Server将一列的多行内容拼接成一行
查看>>
Spring Controller RequestMapping
查看>>
socket
查看>>
小程序 跳转问题 (来源见注明)
查看>>
JBPM4入门——9.自动节点单线执行
查看>>