前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM 学习笔记一 :JVM类加载机制

JVM 学习笔记一 :JVM类加载机制

作者头像
一枝花算不算浪漫
发布2019-11-18 13:25:07
2760
发布2019-11-18 13:25:07
举报

前言:

最近在看JVM相关资料,这里记录下学习笔记,希望自己能坚持学完,打牢基础。

一、类加载过程

1,类从被加载到JVM中开始,到卸载为止,整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。

2,其中类加载过程包括加载、验证、准备、解析和初始化五个阶段。

二、Java类运行过程

我们编写完的程序都是以java结尾的文件,编译写完的代码都会生成一些后缀为class的字节码文件。

当执行java -jar命令后(以springboot为例),此时会启动一个JVM进程,然后通过类加载机制来将所需要的类加载到JVM中进行运行。

这样一个编译好的系统就可以运行起来了。

三、类加载机制

我们都知道类的加载是一个很繁琐的过程,基本流程如下:

加载-》验证-》准备-》解析-》初始化-》使用-》卸载

1、加载

到底什么时候该去加载一个类呢?答案就是在我们使用一个类的时候,以main() 函数为入口,当JVM启动的时候,它会将含有main()函数入口的代码加载然后开始执行。

首先是代码中含有main()函数,然后开始执行main()函数中的代码,接着遇到ReplicaMananger类,此时就会将对应的.class字节码文件加载到内存中。

2、验证|准备|解析

(1)验证阶段

简单来说,这一步就是根据Java虚拟机规范,来校验你加载进来的”.class”文件中的内容,是否符合指定的规范。

所以把”.class”加载到内存里之后,必须先验证一下,校验他必须完全符合JVM规范,后续才能交给JVM来运行。

(2)准备阶段

例如下面的一个”ReplicaMananger”类:

代码语言:javascript
复制
public class ReplicaMananger {
    Public static int flushInterval;
}

假如有上面的一个类,它的class文件内容刚被加载到内存之后,会进行验证,确认这个字节码文件的内容是规范的,接着进行准备工作。

准备工作其实就是为”ReplicaMananger”类分配一定的内存空间,然后给它里面的变量分配内存空间,来一个默认的初始值。

比如上面的示例中,就会给”flushInterval"这个变量分配内存空间,给一个”0”这个初始值。

(3)解析阶段

解析阶段,实际上就是把符号应用替换为直接引用的过程。

在程序编译时,java类并不知道所引用的类的实际地址,因此只能引用符号引用来替代。例如,在Class文件中它以class_info、fieldref_info、methodref_info等类型的常量出现。 

比如org.simple.People类引用了org.simple.Language类,在编译时,People类并不知道Language类的地址,因此只能使用org.simple.Language(假设是这个,当然实际是由类似于CONSTANT_Class_info的常量来表示的)来标识Language类的地址。直接引用可以是直接指向目标的指针、相对偏移量、一个能间接定位到目标的句柄。

3、核心阶段:初始化

上面说过,在准备阶段,就会给”ReplicaMananger”类给分配好内存空间,另外他的一个默认的初始值为”0”,那么在接下来,在初始化阶段,就会正式执行我们的类初始化代码了。

如上所示,flushInterval这个变量是由Configuration.getInt("replica.flush.interval")这段代码来获取一个值,并且赋值给他的。另外还比如在static静态代码块,也会在这个阶段来执行。

4、总结

一般来说,在new Class() 来初始化类对象时,会触发类的加载到初始化的全过程,把这个类准备好,然后是实例化一个对象出来。

或者是包含main()方法的主类,必须是立马初始化的。

此外,还有一个非常重要的规则,就是如果初始化一个类的时候,发现他的父类还没有初始化,那么必须先初始化他的父类。

四、双亲委托原则

Java中的类加载器

1,启动器加载器:Bootstrap ClassLoader

一旦JVM启动,那么首先就会依托启动类加载器,去加载Java安装目录下的”lib”目录下的核心类库。

2,扩展类加载器: Extension ClassLoader

这个类加载器也是类似的,就是Java安装目录下,有一个”lib\ext”目录,这里有一些类,就是需要使用这个类加载器来加载的。

3,应用程序内加载器:Application ClassLoader

这类加载器就是负责加载ClassPath环境变量中所指定路径中的类,可以理解为加载我们写好的Java代码。这个类加载器就负责加载我们写好的类到内存中。

4,自定义类加载器

除了上面几种,我们还可以自定义类加载器,根据自己的需求加载需要的类。

5,双亲委托机制

JVM类加载器有亲子层级结构的,如下图:

基于这个亲子层级结构,就有一个双亲委派的机制,也就是当我们加载一个类的时候,先找父亲去加载,不行的话再由儿子来加载。这样的话 可以避免多层级的加载器结构重复加载某些类。

6,双亲委派模式的优点:

采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。

其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。 

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-11-17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言:
  • 一、类加载过程
  • 二、Java类运行过程
  • 三、类加载机制
    • 1、加载
      • 2、验证|准备|解析
        • 3、核心阶段:初始化
          • 4、总结
          • 四、双亲委托原则
            • Java中的类加载器
              • 1,启动器加载器:Bootstrap ClassLoader
              • 2,扩展类加载器: Extension ClassLoader
              • 3,应用程序内加载器:Application ClassLoader
              • 4,自定义类加载器
              • 5,双亲委托机制
              • 6,双亲委派模式的优点:
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档