虚拟机类加载机制

1、类加载时机

类生命周期

加载(loading)、验证(Verification)、准备(preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸载(Unloading)
其中,验证、准备、解析统称为链接(linking)

加载时机

1、遇到new、getstatic、pustatic、invokestatic这4个字节码指令,常见场景:new实例、读取或设置一个类的静态字段、以及调用一个类的静态方法;
2、使用java.lang.reflect包的方法对类进行反射调用;
3、初始化一个类,如果其父类还没有初始化时;
4、虚拟机启动,用户需要指定一个要执行的主类(包含main()方法的类);
5、使用JDK1.7动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果时REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个句柄所对应的类没有进行过初始化时,需要先触发其初始化.

被动引用

上述情况被称为主动引用,除此之外,所有引用类的方式都不会触发初始化称为被动引用。
书中列举三种情况:
1、通过子类引用父类的静态字段,不会导致子类初始化;
2、通过数组定义来引用类,不会触发此类的初始化;
3、常量在编译阶段会存入调用类的常量池,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。

2、类加载过程

加载

流程,完成三件事:

  • 过类的全限定名获取定义此类的二进制字节流(多种方式:ZIP包、网络、动态代理、文件、数据库)
  • 这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
  • 内存中生成代表这个类的java.lang.Class对象,作为方法去这个类的各种数据的访问入口

验证

1、文件格式验证:
  • 是否以魔数0xCAFEBABE开头
  • 主次版本号是否在当前虚拟机处理范围之内
  • 常量池种的常量中是否有不被支持的常量类型(检查常量tag标志)
  • 指向常量的各种索引值中是否有指向不存在的常量或不符合类型的常量
  • CONSTANT_Utf8_info型的常量中是否有不符合UTF8编码的数据
  • Class文件中各部分机文件本身是否有被删除或附加的其他信息
    ......
2、元数据验证
  • 这个类是否有父类
  • 父类是否继承了不允许被继承的类(被final修饰的类)
  • 如果这个类不是抽象类,是否实现了其父类或接口中要求实现的所有方法
  • 类中的字段、方法、是否与父类产生矛盾(如覆盖了父类的final字段,或者出现不符合规则的方法重载,例如方法参数都一样,返回值类型却不同等)
    ......
3、字节码验证

对类的方法体进行校验分析,主要目的是通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。如:

  • 保证任意时刻操作栈的数据类型与指令代码序列都能配合工作,例如不会出现这样一种情况:在操作栈放置了一个int类型的数据,使用时却按long类型来加载入本地变量表
  • 保证跳转指令不会跳到方法体以外的字节指令码上
  • 保证方法体中的类型转换是有效的,例如子类赋值给父类数据类型
    ......
4、符号引用验证

虚拟机将符号引用转化为直接引用时,对类自身以外(常量池中的各种符号引用)的信息进行匹配性校验:

  • 符号引用中通过字符串描述的全限定名是否能找到对应的类
  • 指定的类中是否存在符合方法的字段描述符以及简单名称所描述的方法和字段
  • 符号引用中的类、字段、方法的访问性(private、public、protected、default)是否可以被当前类访问
    ......

准备

正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区进行分配。仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在java堆中。其次,都是初始化数据类型的零值。

解析

解析是虚拟机将常量池内的符号引用替换为直接引用的过程。
解析主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用限定符7类符号引用进行。

  • 符号引用:任何形式字面量,引用的目标不一定已加载到内存中
  • 直接引用:直接指向目标的指针、相对偏移量或一个能直接定位到目标的句柄,指向已加载到内存中的目标

初始化

通过程序指定的主观计划去初始化变量和其他资源,从另一个角度讲:初始化是执行类构造器<clinit>()方法的过程

  • <clinit>()是编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{})中的语句合并产生的
  • 与构造函数不同,不需要显示地调用父类构造器,虚拟机保证子类地<clinit>()执行前父类的<clinit>()已执行完
  • 由于父类的<clinit>()先执行,意味着父类中定义的静态语句块要优先于子类的变量赋值操作
  • <clinit>()非必需,如果没有静态语句块,就没有对变量的赋值操作,那么可以不为这个类生成<clinit>()方法
  • 接口不能使用静态语句块,但仍然有变量初始化的赋值操作,一样会生成<clinit>()方法
  • 虚拟机保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,可能会造成进程阻塞,往往很隐蔽。

3、类加载器

虚拟机外部实现类加载阶段地“通过一个类的全限定名来获取描述此类的二进制字节流”的代码模块,称为类加载器。

类与类加载器

判断两个类是否“相等”,只有在这两个类由同一个类加载器加载的前提下才有意义。这里的相等包括equals()方法、isAssignableFrom()方法、isInstance()方法的返回结果,及instanceof关键字做对象所属关系判断等情况。

双亲委派模型

类加载器(前三种为系统提供的类加载器):
  • 启动类加载器(Bootstrap ClassLoader),虚拟机唯一识别的类加载器,加载<JAVA_HOME>\lib文件夹中的类,或被-Xbootclasspath指定的路径中的类
  • 扩展类加载器(Extension ClassLoader),加载<JAVA_HOME>\lib\ext中,或被系统变量java.ext.dirs指定的路径中的类
  • 应用程序加载器(Application ClassLoader),由ClassLoader的getSystemClassLoader()方法的返回值,亦称为系统类加载器,负责加载用户类路径(ClassPath)上指定的类库,如果程序没有自定义类加载器,一般是程序默认的类加载器
  • 自定义类加载器
双亲委派模型

类加载器收到类加载请求,先委派给父类加载器完成,层层网上,如果顶层父类加载器无法加载,子类再尝试加载。保证如java.lang.Object等基础类唯一性,使java类与类加载器一起具备带有优先级的层次关系。

破坏双亲委派模型
  • 双亲委派模型出现之初,为了向下兼容,JDK1.2再java.lang.ClassLoader提供findClass()方法重写类加载逻辑
  • 由于模型自身缺陷,基础类并不总是作为被调用的API,也有可能调回用户代码(如JNDI),引用线程上下文类加载器,父类请求子类加载器去完成加载动作
  • 用户对程序动态性的追求(OSGI),每一个模块都有自己的类加载器,在平级的类中加载类
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,175评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,674评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,151评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,597评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,505评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,969评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,455评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,118评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,227评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,213评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,214评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,928评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,512评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,616评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,848评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,228评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,772评论 2 339

推荐阅读更多精彩内容