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 对象 ...
随机推荐
- html标签详解(2)
http标签详解 声明 1:这里的文字都是我从我自己csdn账号拷贝过来,是本人学习总结的结晶,所以请尊重本作品.2:如要要转载本文章,则要说明文字的出处.3:如有哪里不对欢迎指出. 在上一篇文章中主 ...
- Pulsar Consumer实现介绍
Pulsar-Consumer “Pulsar is a distributed pub-sub messaging platform with a very flexible messaging m ...
- Java 锁优化
一.重量级锁 Java中,Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的.但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock来实现的.而操作系统实现 ...
- 踏上编程大道 从 Python 开始成为神级 Coder
电脑科学,或说计算机科学,是个在美国不断成长的产业,薪资报酬也很高.市场上永远存在著对天赋异禀的新锐工程师的需求,这就是为什麽「学习程式语言」一直是一件有魅力的事情. 但是,就跟任何技能一样,我们常常 ...
- 深入理解Java虚拟机阅读心得(三)
Java中提倡的自动内存管理最终可以归结为自动化的解决两个问题: 给对象分配内存 回收分配给对象的内存 先说说回收这一方面的两个主要知识点 一.垃圾收集算法 1.标记-清理算法 首先标记出所有需要回收 ...
- SpringBoot系列——Thymeleaf模板
前言 thymeleaf是springboot官方推荐使用的java模板引擎,在springboot的参考指南里的第28.1.10 Template Engines中介绍并推荐使用thymeleaf, ...
- Spark内存管理机制
Spark内存管理机制 Spark 作为一个基于内存的分布式计算引擎,其内存管理模块在整个系统中扮演着非常重要的角色.理解 Spark 内存管理的基本原理,有助于更好地开发 Spark 应用程序和进行 ...
- C# Redis安装 使用教程
前言:lz自打工作以来第一次遇到电脑问题需要重装系统,全盘格式化.打击是沉痛的.特别伤. 然后需要重新在本地部署 redis.这是写这篇博客的原因.希望对大家有所帮助,安装资源和引用DLL可以引用 ...
- IdnentiyServer-使用客户端凭据访问API
情景如下:一个客户端要访问一个api,不需要用户登录,但是又不想直接暴露api给外部使用,这时可以使用identityserver添加访问权限. 客户端通过clientid和secrect访问iden ...
- iframe实用操作
iframe高度设置为子页面高度 //需要使用Jquery $(document).ready(function () { parent.document.getEleme ...