JVM 之类加载
一.概述
Java不同于C/C++这类传统的编译型语言,也不同于php这一类动态的脚本语言。可以说Java是一种半编译语言,我们所写的类会先被编译成.class文件,这个.class是一串二进制的字节流。然后当要使用这个类的时候,就会将这个类对应的.class文件加载进内存中。而将这个.class的内容加载进内存,正是通过Jvm类加载机制实现的。
虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
二.类加载的各个步骤
加载
加载时“类加载”过程的第一步,在加载过程中,虚拟机需要完成以下三件事
- 通过一个类的全限定名来获取定义此类的二进制字节流。
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
- 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区的这个类的各种数据的访问入口。
值得一提的是,在加载阶段既可以使用系统提供的引导类加载器来完成,也可以由用户自定义的类加载器来完成,相对而是比较自由的,但对于数组则不是这样了,数组类本身不通过类加载创建,它是由Java虚拟机直接创建的。但数据所存放的元素类型是需要类加载器去创建的。
加载阶段与下一阶段的连接部分是交叉进行的,但加载阶段和连接阶段的开始时间仍然会保持固定的先后顺序。
验证
验证时连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息复合当前虚拟机的要求,并且不会危害虚拟机自身的安全。虽然说数组越界,将对象胡乱转型这些操作会被编译器拒绝编译,但.class文件并不一定要求从Java源码编译而来,可以从其他途径产生,故而需要对.class文件的二进制流进行验证。
验证阶段的重要性是不言而喻的,这一阶段是否严谨,直接决定了Java虚拟机是否能承受恶意代码的攻击,从执行性能的角度上讲,验证阶段的工作量在虚拟机的类加载系统中又占了相当大的一部分。
从整体上看,验证阶段大致可分为4部分的检验动作:文件格式验证,元数据验证,字节码验证,符号引用验证。
- 符号验证:主要目的是保证输入的字节流能正确地解析并存储于方法区之内,格式上符合描述一个Java类型信息的要求。这一部分是基于二进制流验证的,之后会加载到内存中,后续验证是在内存中验证。
- 元数据验证:这一验证主要是对类的元数据信息进行语义校验,保证不存在不符合Java语言规范的元数据信息。
- 字节码验证:这一部分是验证阶段中最复杂的一阶段,主要目的是通过数据流和控制流分析,确定程序是合法的,符合逻辑的。
- 符号引用验证:符号引用是发生在虚拟机将符号引用转化为直接引用的时候,目的是却好解析动作能正常执行。
准备
准备阶段是为正式类变量(静态变量)分配内存并设置类变量初始值的阶段,这些变量所使用的内存都讲在方法区中进行分配的。值得一提的是,这时候进行分配的仅为类变量(静态变量),而不包括实例变量。
通常情况下,设置类变量初始值,这个初始值指的是数据类型的默认值,比如int型则是0。但若类变量被final修饰,则情况又不一样,那样的话会直接对给定值进行赋值。
解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。这里解释以下什么是符号引用,什么是直接引用。
符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义得定位到目标即可。
直接引用:直接引用可以是指向目标的指针,相对偏移量或是一个能间接定位到目标的句柄。
解析动作主要针对类或接口,字段,类方法,接口方法,方法类型,方法句柄和调用点限定符7类符号引用进行。
初始化
类初始化阶段是类加载过程的最后一步,前面的类加载过程,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才会真正开始执行类中定义的Java代码。
在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则根据程序员通过程序制定的计划区初始化类变量和其他资源。
三.有意思的代码段
public class StaticTest
{
public static void main(String[] args)
{
staticFunction();
}
static StaticTest st = new StaticTest();
static
{
System.out.println("1");
}
{
System.out.println("2");
}
StaticTest()
{
System.out.println("3");
System.out.println("a="+a+",b="+b);
}
public static void staticFunction(){
System.out.println("4");
}
int a=110;
static int b =112;
}
这段代码的运行结果是什么呢?
答案是:
2
3
a=110,b=0
1
4
这是为什么呢,大家不妨思考以下。
理解这段代码不光是要明白Java的类加载机制,还需要明白初始化阶段,静态代码块与静态成员变量的初始化顺是与代码顺序有关的。
类加载的过程是:装载–>连接(验证,准备,解析)–>初始化。
1.在准备阶段,会为类变量设置默认值,所以在案例一中:st=null,b=0,
2.在初始化阶段,会先执行类构造器,
换句话说,就是执行static修饰的代码块和为static修饰的变量赋值而已。而static修饰的代码块和类变量的执行顺序是按照它在文件中的先后顺序执行的。而static StaticTest st = new StaticTest()排在第一,所以会执行 new StaticTest(),也就是进行对象的初始化
2.1.在对象的初始化过程中,会先执行成员变量(代码块),然后再执行构造方法.成员变量的执行顺序也是谁先声明,谁先执行,所以排在第一的代码块
2.2成员变量执行完后,执行构造方法.此时,a=110,b=0;
3.由static StaticTest st = new StaticTest();触发的非静态代码的初始化过程到此结束,接下来继续执行静态代码的初始化,于是输出 1 。
4.整个类加载到此结束,执行代码,输出 4 。
再看下一道
public class StaticTest
{
public static void main(String[] args)
{
staticFunction();
}
static
{
System.out.println("1");
}
{
System.out.println("2");
}
StaticTest()
{
System.out.println("3");
System.out.println("a="+a+",b="+b);
}
public static void staticFunction(){
System.out.println("4");
}
int a=110;
static int b =112;
static StaticTest st = new StaticTest(); //将这条语句放到最下面
}
仅仅是改变一条语句,而这段代码的运行结果是
1
2
3
a=110,b=112
4
大家不妨运用上面的知识,想想是为什么。
推荐阅读:
大数据存储的进化史 --从 RAID 到 Hdfs
贝叶斯分类算法实例 --根据姓名推测男女
从分治算法到 MapReduce
JVM 之类加载的更多相关文章
- JVM学习一:JVM之类加载器概况
18年转眼就3月份都快结束了,也就是说一个季度就结束了:而我也因为年前笔记本坏了,今天刚修好了,那么也应该继续学习和博客之旅了.今年的博客之旅,从JVM开始学起,下面我们就言归正传,进入正题. 一.J ...
- JVM的类加载
一.基本类加载机制介绍 大体引用一下<深入理解Java虚拟机>一书中对类加载的定义:虚拟机将描述类的二进制字节流(即Class文件)加载到内存中,并对其进行验证.准备.解析.初始化,最终 ...
- (转) JVM——Java类加载机制总结
背景:对java类的加载机制,一直都是模糊的理解,这篇文章看下来清晰易懂. 转载:http://blog.csdn.net/seu_calvin/article/details/52301541 1. ...
- JVM自定义类加载器加载指定classPath下的所有class及jar
一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责 ...
- JVM内存结构 JVM的类加载机制
JVM内存结构: 1.java虚拟机栈:存放的是对象的引用(指针)和局部变量 2.程序计数器:每个线程都有一个程序计数器,跟踪代码运行到哪个位置了 3.堆:对象.数组 4.方法区:字节流(字节码文件) ...
- JVM之类加载机制
JVM之类加载机制 JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 类加载五部分 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这 ...
- JVM——自定义类加载器
)以上两种情况在实际中的综合运用:比如你的应用需要通过网络来传输 Java 类的字节码,为了安全性,这些字节码经过了加密处理.这个时候你就需要自定义类加载器来从某个网络地址上读取加密后的字节代码,接着 ...
- 深入理解JVM的类加载
前言: 前面又说到Java程序实际上是将.class文件放入JVM中运行.虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验,转换,解析和初始化,最终形成可以被虚拟机直接使用的Java类 ...
- JVM的类加载机制全面解析
什么是类加载机制 JVM把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被JVM直接使用的Java类型,这就是JVM的类加载机制. 如果你对Class文件的结 ...
- JVM的类加载过程以及双亲委派模型详解
JVM的类加载过程以及双亲委派模型详解 这篇文章主要介绍了JVM的类加载过程以及双亲委派模型详解,类加载器就是根据指定全限定名称将 class 文件加载到 JVM 内存,然后再转化为 class 对象 ...
随机推荐
- HP服务器设置iLO
HP服务器设置iLO步凑 1.开机出现界面—按下F11进入Boot Menu: 2.选择Generic USB Boot回车: 3.选择System Configuration回车: 4.选择iLO ...
- mysql 开发基础系列1 表查询操作
在安装完数据库后,不管是windows 还是linux平台, mysql的sql命令都大同小异,相关命令都是相同的,每个命令结束后 都以 ; 结尾, 注意在windows平台中表名是不区分大小写 ...
- JVM学习(一)、垃圾收集器简介
一.垃圾收集算法 (1)标记-清除算法:最基础的收集算法“标记--清除”(Mark-sweep)算法,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的 ...
- 一个前端开发者换电脑的过程(git篇)
一,安装git. 要安装git,首先得把它下载下来.去到git官网. 现在开始安装. 讲真,这些东西哪些要勾哪些不要勾我也不清楚,所以全部都按默认的来,一路next. 现在再打开vscode的终端,发 ...
- Spring Boot (三)模板引擎FreeMarker集成
一.FreeMaker介绍 FreeMarker是一款免费的Java模板引擎,是一种基于模板和数据生成文本(HMLT.电子邮件.配置文件.源代码等)的工具,它不是面向最终用户的,而是一款程序员使用的组 ...
- WinFrom Thread里面new出来的控件不显示
那本More Effective C# 好多天没看了..惭愧. 做个小笔记吧. 今天碰到一个问题,描述如题. 何解?其实很简单,因为Thread里面new出来的控件的Parent是null,然后他就不 ...
- Mybatis学习(四)————— 高级映射,一对一,一对多,多对多映射
一.单向和双向 包括一对一,一对多,多对多这三种情况,但是每一种又分为单向和双向,在hibernate中我们就详细解析过这单向和双向是啥意思,在这里,在重复一遍,就拿一对多这种关系来讲,比如有员工和部 ...
- 2016 ACM/ICPC亚洲区青岛站现场赛(部分题解)
摘要 本文主要列举并求解了2016 ACM/ICPC亚洲区青岛站现场赛的部分真题,着重介绍了各个题目的解题思路,结合详细的AC代码,意在熟悉青岛赛区的出题策略,以备战2018青岛站现场赛. HDU 5 ...
- 利用反射跟自定义注解拼接实体对象的查询SQL
前言 项目中虽然有ORM映射框架来帮我们拼写SQL,简化开发过程,降低开发难度.但难免会出现需要自己拼写SQL的情况,这里分享一个利用反射跟自定义注解拼接实体对象的查询SQL的方法. 代码 自定义注解 ...
- Entity Framework Core 中文入门文档
点击链接查看文档: Entity Framework Core 中文入门文档