JAVA 类加载过程详细讲解 -jvm加载类机制CLass Loading

news/2024/7/4 1:26:15 标签: java, jvm, class, 内存
class="baidu_pl">
class="article_content clearfix">
class="htmledit_views">

class="tags" href="/tags/JVM.html" title=jvm>jvm加载类机制CLass Loading

前提:class="tags" href="/tags/JAVA.html" title=java>java源文件被class="tags" href="/tags/JAVA.html" title=java>javac编译为class字节码文件。
class="tags" href="/tags/JAVA.html" title=java>javac编译时不进行连接(分配内存)工作,而是在class="tags" href="/tags/JVM.html" title=jvm>jvm运行时才动态加载和动态连接

什么是类的加载

class="tags" href="/tags/JVM.html" title=jvm>jvm将class文读取到内存中,经过对class文件的校验、转换解析、初始化最终在class="tags" href="/tags/JVM.html" title=jvm>jvm的heap和方法区分配内存形成可以被class="tags" href="/tags/JVM.html" title=jvm>jvm直接使用的类型的过程。

类的生命周期

7个阶段依次为:Loading Verification Preparation Resolution Initialization Using Unloading

加载 验证 准备 初始化和卸载 的顺序是确定的,而“解析”不一定在初始化之前,很有可能在初始化之后,实现class="tags" href="/tags/JAVA.html" title=java>java的伟大特性

运行时(晚期)绑定

一个阶段的执行过程中会调用或激活另一个阶段

分阶段解释

1、加载Loading

这个阶段class="tags" href="/tags/JVM.html" title=jvm>jvm完成以下动作:
首先  类加载器通过类的全路径限定名读取类的二进制字节流,
然后  将二进制字节流代表的类结构转化到运行时数据区的 方法区中,
最后  在class="tags" href="/tags/JVM.html" title=jvm>jvm堆中生成代表这个类的class="tags" href="/tags/JAVA.html" title=java>java.lang.Class实例(不是这个类的实例)

类加载器

获取类的二进制流 既可以使用class="tags" href="/tags/JVM.html" title=jvm>jvm自带的类加载器,也可以自己写加载器来加载,这一小步是完全可控的。不同的加载器可以从各种地方读取:zip包jar包,class文件,网络流 。。。读取类的二进制字节流

同一个加载器加载的同源类才是真的同类。不同加载器加载同源类,不是同类!instanceof为FALSE

类加载的双亲委派模型

各个加载器都是先委托自己的父加载器加载类,若确实没加载到再自己来加载

于是class="tags" href="/tags/JAVA.html" title=java>java默认的类查找加载顺序是自顶向下的,树状结构

双亲委托的意图是保证class="tags" href="/tags/JAVA.html" title=java>java类型体系中最基础的行为一致,优先加载JDK中的类

加载器主要有四种:

  • class="tags" href="/tags/JVM.html" title=jvm>jvm启动类加载器bootstrap loader,用c++实现为class="tags" href="/tags/JVM.html" title=jvm>jvm的一部分(仅指sun的hotspot),负责 JAVA_HOME/lib下面的类库中的类的加载,这个加载器,class="tags" href="/tags/JAVA.html" title=java>java程序无法引用到。

  • 扩展类加载器Extension Loader,由sun.misc.Launcher$ExtClassLoader类实现,可在class="tags" href="/tags/JAVA.html" title=java>java中使用,负责JAVA_HOME/lib/ext 目录和class="tags" href="/tags/JAVA.html" title=java>java.ext.dir目录中类库的类的加载。

  • 应用系统类加载器Application System Loader,由sun.misc.Louncher$AppClassLoader实现,负责加载用户类路径中类库中的类,如果没有使用自定义的加载器,这个就是默认的 加载器!

  • 用户自定义加载器 自己定义从哪里加载类的二进制流

OSGi的网状加载模型

双亲委派是class="tags" href="/tags/JAVA.html" title=java>java设计者推荐的类加载器实现方式,可以在遵循的基础上扩展,自定义类加载器的实现机制。

OSGi事实上的class="tags" href="/tags/JAVA.html" title=java>java模块化标准,他自定义的类加载器,能很多好实现模块化和模块的热部署:更换一个bundle时,连同这个bundle的类加载器一同换掉。

OSGi中class="tags" href="/tags/JAVA.html" title=java>java.*开头的类按照双亲加载机制加载,而其他类则都是由平级的类加载器加载的,形成一张网。 

2、验证verification

Loading和 验证是交叉进行的,验证二进制字节流代表的字节码文件是否合格,主要从一下几方面判断:

文件格式:参看class文件格式详解,经过文件格式验证之后的字节流才能进入方法区分配内存来存储

元数据验证:是否符合class="tags" href="/tags/JAVA.html" title=java>java语言规范

字节码验证:数据流和控制流的分析,这一步最复杂

符号引用验证:符号引用转化为直接引用时(解析阶段),检测对类自身以外的信息进行存在性、可访问性验证

如果确认代码安全无误,可用 -Xverify:none关闭大部分类的验证,加快类加载时间

3、准备preparation

在方法区中给类的类变量(static修饰)分配内存

然后初始化其值,如果类变量是常量,则直接赋值为该常量值否则为class="tags" href="/tags/JAVA.html" title=java>java类型的默认的零值。


4、解析resolution

指将常量池内的符号引用替换为直接引用的过程。未理解 再调研


5、初始化initialization

这个阶段才真正开始执行class="tags" href="/tags/JAVA.html" title=java>java代码,静态代码块和设置变量的初始值为程序员设定的值

主动引用

有且只有下面5种情况才会立即初始化类,称为主动引用:

  • new 对象时

  • 读取或设置类的静态字段(除了 被final,已在编译期把结果放入常量池的 静态字段)或调用类的静态方法时;

  • class="tags" href="/tags/JAVA.html" title=java>java.lang.reflect包的方法对类进行反射调用没初始化过的类时

  • 初始化一个类时发现其父类没初始化,则要先初始化其父类

  • 含main方法的那个类,class="tags" href="/tags/JVM.html" title=jvm>jvm启动时,需要指定一个执行主类,class="tags" href="/tags/JVM.html" title=jvm>jvm先初始化这个类

其他对类的引用 称为被动引用,加载类时不会进行初始化动作

子类继承父类时的初始化顺序

   1.首先初始化父类的static变量和块,按出现顺序

   2.初始化子类的static变量和块,按出现顺序

   3.初始化父类的普通变量,调用父类的构造函数

   4.初始化子类的普通变量,调用子类的构造函数

类的初始化过程发生时刻: 

1. T是一个类,当T的一个实例创建的时候,也就是T t = new T(); 

2. T的一个静态方法被调用的时候,也就是 T.staticField(); 

3. T的静态属性被赋值的时候,T.staticField = o; 

4. T的一个静态属性被使用的时候,也就是 Object o = T.staticField; 但是它不是常量。 

5. T is a top level class , and an assert statement  lexically nested 


http://www.niftyadmin.cn/n/1393428.html

相关文章

/proc/uptime详解

From:http://smilejay.com/2012/05/proc_uptime/ 在Linux中,我们常常会使用到uptime命令去看看系统的运行时间,它与一个文件有关,就是/proc/uptime,下面对其进行详细介绍。 1 2 3 4masterjay-intel:~$ cat /proc/uptime 6447032.…

使用 VMware Workstation6 在 Oracle Enterprise Linux 5上安装 Oracle 11gR1(下)

5.与特定产品相关的先决条件的检查 <?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />如果您一直在依循本指南中的步骤&#xff0c;则所有检查都应顺利通过。如果一个或多个检查失败&#xff0c;则在继续操作前纠正该问题。6.选择…

Linux下Ansible Playbooks中模板及变量的使用(四)

续我的上篇博文&#xff1a;https://mp.csdn.net/postedit/88874695。即httpd.yml文件已经编写好&#xff0c;自动化部署zabbix已经配置好&#xff08;但是需要在此基础上再添加一个主机server3&#xff09;。本篇博文只是修改上篇博文编写的httpd.yml文件 一、temaplate的使用…

java 经典算法

【Java算法学习】斐波那契数列问题-兔子产子经典问题 题目&#xff1a;如果一对两个月大的兔子以后每个月可以生一对兔子&#xff0c;而一对新生的兔子出生两个月后才可以生兔子。也就是说1月份出生的3月份才能生子。假定一年内兔子没有死亡事件&#xff0c;那么一年后共有多少…

perl 内部变量

perl 内部变量$^O 判断操作系统的类型ARGV 传给脚本的命令行参数列表_ 传给子程序的参数列表$ ()匹配前面部分的内容$& &#xff08;&#xff09;匹配中间部分的内容$ &#xff08;&#xff09;匹配后面部分的内容$$ 进程ID$0-9 位置参数$! 系统返回错误信息$ eval语句计算…

TCP3次握手连接协议和4次握手断开连接协议

TCP/IP 状态机&#xff0c;如下图所示&#xff1a;在TCP/IP协议中&#xff0c;TCP协议提供可靠的连接服务&#xff0c;采用三次握手建立一个连接&#xff0c;如图1所示。 (SYN包表示标志位syn1,ACK包表示标志位ack1,SYNACK包表示标志位syn1,ack1)(1) 第一次握手&#xff1a;建立…

Linux下利用自动化运维工具Ansible自动化部署zabbix

续我的博文&#xff1a;https://mp.csdn.net/postedit/88865995。即Ansible已经部署好。 一、实验环境(rhel7.3版本) 1.selinux和firewalld状态为disabled 2.各主机信息如下&#xff1a; 主机ipserver1&#xff08;ansible的服务端&#xff09;172.25.83.1server2&#xff0…

JVM 内存 (堆(heap)、栈(stack)和方法区(method) )

JAVA的JVM的内存可分为3个区&#xff1a;堆(heap)、栈(stack)和方法区(method) 堆区: 1.存储的全部是对象&#xff0c;每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令) 2.jvm只有一个堆区(heap)被所有线程共享&#xff0c;堆中不存放基本类型和对象引用…