JVM类加载机制总结
1.运行时加载优点
提高灵活性,可以在运行时动态加载,连接。例子:面向接口编程,动态绑定实现类(但C++也有动态绑定,说明动态绑定不一定通过运行时加载Class字节码实现,也可能是机器码支持的)
2.编译并在运行时动态加载字节码优点
可在运行时动态获取二进制字节流作为动态代码,比如可以从网络上获取;可以做一个循环,动态从某文件库获取;可以从指定的ClassPath路径获取,比如一个jar包目录
3.与动态类型语言的区别
动态类型语言如JS,可在运行时添加类型属性,方法,在运行时改变类型行为
4.类加载生命周期
加载、验证、准备、解析、初始化、使用、卸载。按这个顺序开始,但交叉执行。验证、准备、解析统称为连接。解析阶段不一定按这个顺序,可以在初始化之后,为了支持上文的动态绑定(运行时绑定)。
5.必须“初始化”(类加载第5阶段)的几种情况(主动引用,有且仅有这些情况时要初始化,初始化钱当然要先“加载”,所以也是必须加载的几种情况)
new实例化对象、读取或设置类static非final字段(final static在编译时存入常量池)、调用类静态方法、类反射调用、初始化一个类时先初始化其父类、虚拟机启动的带main方法的执行主类(虚拟机执行入口)等。
6.不会激发“初始化”的情况(被动引用)
a.引用子类使用其父类的static非final字段(直接定义这个字段的类),只会初始化父类,不会初始化子类。子类是否加载、验证(类加载第1,2阶段),取决于虚拟机具体实现,无规定
b.通过数组定义引用类,不会触发该类初始化。这里触发了一个虚拟机自动生成的代表数组的类的初始化,里面有数组相关属性,比如public的length字段(数组长度)
c.一个类引用另一个类的public static final字段,不会初始化另一个类。该字段引用在编译时进入了前一个类(引用类)的常量池中,编译后就与后一个类完全没关系了。
d.接口初始化:不要求初始化其父类接口,这与类初始化不同。只有使用到父接口比如引用其常量时才会初始化父类接口
7.类加载过程
加载阶段:一个非数组类的加载是开发人员可控性最强的,可以使用系统的引导类加载器,也可使用用户自定义类加载器控制字节流获取方式(下面a所述),即重写loadClass方法。数组类由虚拟机创建,其元素类型由类加载器加载。
a.通过类全限定名获取其字节流,方式:zip/jar/war、网络、运行时计算生成(主要指动态代理生成的"*$Proxy"代理类Class文件)、其他文件生成(如jsp)、数据库读取等
b.字节流静态存储结构转换成方法区运行时数据结构
c.内存中生成代表该类的java.lang.Class对象,作为方法区类数据访问入口
验证阶段:
a.文件格式验证:如魔数开头、主次版本号、常量类型、不符合UTF8的编码
b.元数据验证:语义校验,比如是否有父类、是否继承final类(不允许继承)、是否实现接口、是否覆盖了父类final方法(不允许覆盖)
c.字节码验证:数据流与控制流验证,语义是否合法、符合逻辑。方法体校验:操作数栈数据类型是否与指令码使用类型匹配、指令是否跳到方法体外、方法体内类型转换是否有效
d.符号引用验证:符号引用转为直接引用是在解析阶段进行的,这里是对类自身以外(常量池中各种符号引用)的信息进行匹配校验,比如全限定名是否能找到该类、指定类是否有该符号引用所引用的方法和字段、引用的类、方法、字段访问性(private,protected,public,default)是否可被当前类引用,抛出对应IllegalAccessError、NoSuchMethodError等。
准备阶段:
在方法区将类变量(static)分配内存并设置初始值,通常赋类型零值。如public static int value=123;是赋值为0不是123.赋值123是putstatic指令,在类构造器<clinit>()中,是在初始化阶段才执行的。但public static int value=123;则在准备阶段赋值123.
解析阶段:
将常量池内符号引用替换为直接引用。符号引用:目标不一定已加载入内存。直接引用:直接指向目标的指针、相对偏移量或可间接定位的句柄。引入目标必定在内存中存在。
解析的7类符号引用:类或接口、字段、类方法、接口方法、方法类型、方法句柄、调用点限定符。
递归加载这些符号引用解析成直接引用后的那些类、父类、接口、父接口,进内存,然后使用直接引用指向它们。
初始化阶段:
执行类构造器<clinit>()方法的过程。
<clinit>()方法由编译器自动搜集所有类变量赋值动作和static{}块合并产生,顺序由源文件中出现顺序决定。static{}块可赋值在其后定义的变量,但不可访问。
public class Test {
static {
i = 0;//正常编译
System.out.println(i);//非法向前引用!!
}
static int i = 1;
}
父类<clinit>()方法先于子类<clinit>()执行,由虚拟机调用,而不是子类<clinit>()方法调用。因此父类静态块要优先于子类变量赋值动作。(值为多少的面试题)
static class Parent {
public static int A = 1;
static {
A = 2;
}
}
static class Sub extents Parent {
public static int B = A;
}
public static void main(String[] args) {
System.out.println(Sub.B);
}
B值为2.
接口没有静态块。<clinit>()方法用于变量初始化赋值。不需要先执行父类接口<clinit>()方法,使用时执行。实现接口的类初始化也不需要执行接口<clinit>(),使用时执行。
虚拟机保证<clinit>()方法多线程下安全。如多线程执行,其他线程会阻塞,但退出后其他线程也不会再进入执行。同一个类加载器下(一个类与其加载器一起确定唯一性),一个类型只初始化一次!
JVM类加载机制总结的更多相关文章
- JVM基础系列第7讲:JVM 类加载机制
当 Java 虚拟机将 Java 源码编译为字节码之后,虚拟机便可以将字节码读取进内存,从而进行解析.运行等整个过程,这个过程我们叫:Java 虚拟机的类加载机制.JVM 虚拟机执行 class 字节 ...
- JVM总结(四):JVM类加载机制
这一节我们来总结一下JVM类加载机制.具体目录如下: 类加载的过程 类加载过程概括 说说引用 详解类加载全过程: 加载 验证 准备 解析 初始化 虚拟机把描述类的数据从Class文件加载到内存,并对数 ...
- JVM 类加载机制详解
如下图所示,JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的java.lan ...
- Java虚拟机(四):JVM类加载机制
1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构 ...
- JVM类加载机制详解(二)类加载器与双亲委派模型
在上一篇JVM类加载机制详解(一)JVM类加载过程中说到,类加载机制的第一个阶段加载做的工作有: 1.通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件).而获取的方式,可 ...
- JVM类加载机制(转)
原文出自:http://www.cnblogs.com/ityouknow/p/5603287.html 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运 ...
- JVM类加载机制详解
引言 如下图所示,JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 加载 在加载阶段,虚拟机需要完成以下三件事情: 1)通过一个类的全限定名来获取定义此 ...
- Android动态加载--JVM 类加载机制
动态加载,本质上是通过JVM类加载机制将插件模块加载到宿主apk中,并通过android的相关运行机制,实现插件apk的运行.因此熟悉JVM类加载的机制非常重要. 类加载机制:虚拟机把描述类的数据从C ...
- Java虚拟机(五):JVM 类加载机制
一.JVM 类加载机制 JVM 类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 1. 加载: 加载是类加载过程中的第一个阶段,这个阶段会在内存中生成一个代表 ...
- 深入理解JVM虚拟机6:深入理解JVM类加载机制
深入理解JVM类加载机制 简述:虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 下面我们具体 ...
随机推荐
- 【aws】
云服务器EC2 动态调整云服务器ec2 cpu.内存大小: 在ec2实例上右键,Instance settings--> Change Instance Type 选择一个合适的type 云数据 ...
- Python开发【笔记】:关于子线程(子进程)与主线程(主进程)的关联
前言: 主要分析下面的问题: 主线程启线程 主线程执行完毕,会关闭子线程吗? 子线程启线程 主线程执行完毕,会结束吗? 主进程启动进程,主进程执行完毕,会怎样? 子进程启动进程,进程执行完毕,又会 ...
- 深入浅出REST(转载)
add by zhj: 参考http://zh.wikipedia.org/zh/REST 需要注意的是,REST是设计风格而不是标准,它也并没有与哪种协议绑定.不过,我们常按REST设计风格来使用H ...
- Hadoop的那些事儿(转)
原文:http://www.searchtb.com/tag/mapreduce 在说Hadoop之前,作为一个铁杆粉丝先粉一下Google.Google的伟大之处不仅在于它建立了一个强悍 ...
- 集成RabbitMQ做秒杀
由于秒杀的并发量太大,所以仅仅使用缓存是不够的,还需要用到RabbitMQ. 这里推荐一款用于分库分表的中间件:mycat 解决超卖的问题(看第五章节): 秒杀接口优化: 实操: 然后把下载好的文件上 ...
- 【Loadrunner】【浙江移动项目手写代码】代码备份
vuser_init(){ lr_start_transaction("login"); web_url("10.78.224.136:8080" ...
- JVM学习笔记-内存管理
第一章 内存分配 1. 内存区域. 方法区和堆(线程共享),程序计数器 , VM栈 和 本地方法栈(线程隔离). 1) java虚拟机栈:线程私有.描写叙述的是java方法执行的内存模 ...
- PHP 接收筛选项包含0的select下拉菜单的处理
这种情况下,PHP的判断方法如下: $where = "1=1"; if ($get['status'] !== '' && $get['status'] !== ...
- python sys.path[0] 的解释
sys.path是python的搜索模块的路径集,返回的结果是一个list path[0] 此列表的第一项,path[0],在程序启动时初始化,是包含用来调用Python解释器的脚本的目录.如果脚本目 ...
- html07
1.复习js的外部对象,DOM,BOMBOM window -location -Location对象 : href reload() -history -History :back() forwar ...