通俗讲解JVM的类加载机制

前言

我们很多小伙伴平时都是做JAVA开发的,那么作为一名合格的工程师,你是否有仔细的思考过JVM的运行原理呢。

如果懂得了JVM的运行原理和内存模型,像是一些JVM调优、垃圾回收机制等等的问题我们才能有一个更清晰的概念。

为了走进JVM,深入了解底层,王子打算写一个JVM的专题,留下自己对JVM探索的足迹,同时也希望能帮到小伙伴们更好的理解JVM。

那我们开始吧。

JAVA代码的运行流程

首先我们就来聊一聊JAVA代码是怎么运行起来的,这部分比较基础相信大家都知道,就当成是个复习吧。

我们编写的代码都是在java文件中编写的,然后会编译成class字节码文件。

当我们使用到哪个类的时候就会通过类加载器把class字节码文件中的类加载到jvm内存中,然后就是在jvm内存中运行我们的代码了。

整体的运行流程就是这样,相信小伙伴们都很清楚这些,但是有关类加载器是如何把类加载到jvm内存中的,小伙伴们有考虑过吗?

今天我们主要就是聊这一部分。

JVM什么时候加载类

其实说到类加载的底层机制,这是一个很复杂的过程,但是对于我们平时的工作来讲,只要懂得它的核心原理就可以了。

一个类的加载过程会经历如下的几个过程:

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

首先我们就先弄明白一个问题,jvm是什么时候去加载类的呢?

其实答案很简单,就是我们什么时候使用到了这个类,它就去class字节码文件中去加载这个类。

而作为程序的入口,具有main方法的类,肯定是最开始的时候就加载到jvm中了。

对于加载类的时间点问题,其实就是这么简单。

类加载器和双亲委派机制

既然我们知道了类加载的时间点,那么jvm是通过什么方式对类进行加载的呢?就是类加载器。

那接下来我们就来聊聊jvm的类加载器。

jvm的类加载器总体上可以分成4层,我们一起看一下。

1.启动类加载器

首先就是jvm启动的第一道关口,启动类加载器Bootstrap ClassLoader,它主要是加载java的核心类。

相信大家都知道,无论是什么环节下运行java程序,都是要安装jvm虚拟机环境的,而在这个环境的目录中是有一个lib文件夹的,这个文件下就是java最核心的类库,支撑着java系统的运行。

所以一旦jvm启动,那么首先就会通过启动类加载器去加载lib文件夹下的核心类库。

2.扩展类加载器

然后我们就到了第二层,扩展类加载器Extension ClassLoader,这个类加载器其实与启动类加载器是类似的。

在我们的jvm虚拟机环境目录下,是有一个lib/ext的文件夹的,这里面的类就是java运行环境的一些扩展类,这些扩展类就是在jvm启动后,通过扩展类加载器进行加载的。

3.应用程序类加载器

加载完核心类库和扩展类,这时候就到了第三层,应用程序类加载器Application ClassLoader,这个类加载器你就可以理解成是加载我们写好的java代码的就可以了。

4.自定义类加载器

前面的三层就是基本的类加载器了,然后第四层是自定义类加载器,根据一些特殊的需求来自己定义类加载器加载我们的类。

整体上类加载器就是这么的4层结构。很多小伙伴可能都听说过双亲委派机制,那么什么是双亲委派机制呢,王子就和大家用最接地气的语言描述一下。

其实很好理解,就是当我们的类加载器要加载一个类的时候,它首先会委派给它的父亲去加载,但是如果它的父亲没找到就会把这个事交给他的孩子自己去完成了。

这就是双亲委派机制。

举个例子,假如我们的应用程序类加载器要加载一个类A,那么首先它会先回家找它老爸扩展类加载器,问问“老爸,你那有这个类A吗?”

然后扩展类加载器接到这个请求之后,同样也懒得处理,再去找它爷爷启动类加载器。

它爷爷找了一圈没找到类A,很生气,就对扩展类加载器说,“我这没有,你自己找去!”

然后扩展类加载器就灰溜溜的自己找了一圈,同样也没找到,这时候就找到应用类加载器了,说:“我这哪有你这个类A,这明明是你自己应该干的活,爱上哪找上哪找去,我不管了”。

这时候应用类加载器就只能自己去处理了,找了一圈发现找到了类A,就把它加载到jvm内存中了。

相信大家看了这个例子应该很容易理解了吧。

所以假设我们自己创建了一个类java.lang.String,它是不会被应用类加载器加载到内存中的,因为父类中可以找到这个类,就直接给加载到内存中了。

聊聊验证、准备、解析、初始化阶段

聊完了加载,我们再来看看验证、准备、解析、初始化这几个阶段jvm都做了什么。

1.验证阶段

这一步其实很容易理解,就是jvm根据java规范,来校验你加载进来的class文件中的内容是否符合规范,如果不符合规范jvm是无法正常运行的。

所以在加载后,首先就是验证阶段。

2.准备阶段

假设我们有一个类A,刚刚加载并通过了验证,那么就会进行准备工作。

这个准备工作其实就是给类A分配一定的内存空间,然后给里面的静态变量(static修饰的变量)也分配内存空间,并赋初始值。

3.解析阶段

这个阶段干的事实际上是把符号引用替换为直接引用,这一过程网上有很多资料,还是比较复杂的,如果感兴趣小伙伴们可以自己查阅一下资料。

实际工作中也很少会接触这部分的内容,所以我们知道有这么个阶段就可以了。

4.初始化阶段

在准备阶段,我们把类A的内存已经分配完了,那么初始化阶段要做些什么事呢?我们先看一下类A的代码

public class A {
  private static String i=System.getProperty("i");
}

准备阶段我们只是给变量i分配了内存空间,并赋值了初始值,但是后边的System.getProperty("i")是不会执行的。

没错,这部分代码就是在初始化阶段执行的,另外静态代码块也会在这一阶段执行。

举个例子,比如我们新建一个对象new A(),此时就会触发从加载到初始化的全过程,把这个类准备好并创建一个实例对象。

此外这里有一个规则,如果类A继承了类B,那么在初始化类A的时候,如果发现类B还没有初始化,会先初始化类B。

扩展

到这里关于JVM的类加载机制其实就已经说完了,王子再给大家扩展一个小知识点。

小伙伴们想过没有,Tomcat也是用java开发的,那么它的类加载机制是什么样的呢,为什么就能支持jsp呢?

其实它就是利用了自定义类加载器这一机制,自己自定义了很多类加载器,整体的结构如下:

Tomcat自定义了这么多的类加载器,用来加载它自己的核心类库,并且Tomcat是打破了双亲委派机制的,感兴趣的小伙伴可以自己去查资料了解一下,王子就不在本篇文章长篇大论来聊Tomcat了。

总结

今天我们聊的内容还是jvm中比较基础的部分,以后的文章我们再慢慢深入,去探索jvm的底层原理,如果对JVM感兴趣的小伙伴可以关注王子的后续文章哦,我们可以一步一个脚印的逐步分解JVM,去了解JVM的垃圾回收机制、性能调优等等实用性问题,让你面对JVM的面试或者生产实践也可以游刃有余。

那我们下次见。

以上就是通俗讲解JVM的类加载机制的详细内容,更多关于JVM 类加载机制的资料请关注我们其它相关文章!

(0)

相关推荐

  • jvm之java类加载机制和类加载器(ClassLoader)的用法

    当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载.连接.初始化3个步骤来对该类进行初始化.如果没有意外,JVM将会连续完成3个步骤,所以有时也把这个3个步骤统称为类加载或类初始化. 一.类加载过程 1.加载 加载指的是将类的class文件读入到内存,并为之创建一个java.lang.Class对象,也就是说,当程序中使用任何类时,系统都会为之建立一个java.lang.Class对象. 类的加载由类加载器完成,类加载器通常由JVM提供,这些类加载器也是前面所有程序运行的基础

  • JVM的类加载过程以及双亲委派模型详解

    jvm 的主要组成部分 类加载器(ClassLoader) 运行时数据区(Runtime Data Area) 执行引擎(Execution Engine) 本地库接口(Native Interface) jvm 运行时数据区的组成 方法区: ①方法区主要用来存储已被虚拟机加载的类信息(构造器,接口定义).常量.静态变量和运行时常量池等数据. ②该区域是被线程共享的. ③方法区里有一个运行时常量池,用于存放静态编译产生的字面量和符号引用.该常量池具有动态性,也就是说常量并不一定是编译时确定,运行

  • jvm类加载器基础解析

    [类加载器简介] 类加载器(classloader)用于将类的class文件加载到JVM虚拟机.JVM有三种加载器,引导类加载器器(bootstrapclassloader).扩展类加载器(extensionsclassloader)和应用类加载器(applicationclassloader),另外还可以继承java.lang.ClassLoader类创建自定义加载器. [类加载器种类] 1.引导类加载器(BootStrap):并不是一个Java类,采用C++语言编写.内嵌在JVM内核里面,使

  • 从JVM分析Java的类的加载和卸载机制

    类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构. 加载.class文件的方式: 1.从本地系统中直接加载 2.通过网络下载.class文件 3.从zip,jar等归档文件中加载.class文件 4.从专有数据库中提取.class文件 5.将Java源文件动态编译为.class文件 类的加载的最终产品是位于堆区中的Class对象. Class对象封装了类在

  • JVM类加载机制详解

    一.先看看编写出的代码的执行过程: 二.研究类加载机制的意义 从上图可以看出,类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行. 研究类加载机制的第二个目的是让程序能动态的控制类加载,比如热部署等,提高程序的灵活性和适应性. 三.类加载的一般过程 原理:双亲委托模式 1.寻找jre目录,寻找jvm.dll,并初始化JVM: 2.产生一个Bootstrap Loader(启动类加载器): 3.Bootstrap Loader自动加载E

  • JVM核心教程之JVM运行与类加载全过程详解

    为什么要使用类加载器? Java语言里,类加载都是在程序运行期间完成的,这种策略虽然会令类加载时稍微增加一些性能开销,但是会给java应用程序提供高度的灵活性.例如: 1.编写一个面向接口的应用程序,可能等到运行时再指定其实现的子类: 2.用户可以自定义一个类加载器,让程序在运行时从网络或其他地方加载一个二进制流作为程序代码的一部分:(这个是Android插件化,动态安装更新apk的基础) 为什么研究类加载全过程? 有助于连接JVM运行过程 更深入了解java动态性(解热部署,动态加载),提高程

  • JVM加载一个类的过程

    类的加载过程 Java源代码被编译成class字节码,JVM把描述类数据的字节码.Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型,这就是虚拟机的类加载机制. 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的生命周期包括了:加载(Loading).验证(Verification).准备(Preparation).解析(Resolution).初始化(Initialization).使用(Using).卸载(Unloading)七个阶段,

  • 深入理解JVM之类加载机制详解

    本文实例讲述了深入理解JVM之类加载机制.分享给大家供大家参考,具体如下: 概述 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 与那些在编译时需要进行链接工作的语言不同,在Java语言里,类型的加载.连接和初始化过程都是在程序运行期间完成的,例如import java.util.*下面包含很多类,但是,在程序运行的时候,虚拟机只会加载哪些我们程序需要的类.这种策略虽然会令类加载时稍微增加

  • 详解JVM类加载机制及类缓存问题的处理方法

    前言 大家应该都知道,当一个Java项目启动的时候,JVM会找到main方法,根据对象之间的调用来对class文件和所引用的jar包中的class文件进行加载(其步骤分为加载.验证.准备.解析.初始化.使用和卸载),方法区中开辟内存来存储类的运行时数据结构(包括静态变量.静态方法.常量池.类结构等),同时在堆中生成相应的Class对象指向方法区中对应的类运行时数据结构. 用最简单的一句话来概括,类加载的过程就是JVM根据所需的class文件的路径,通过IO流的方式来读取class字节码文件,并通

  • 浅谈JVM核心之JVM运行和类加载

    前言 本篇博客将写一点关于JVM的东西,涉及JVM运行时数据区.类加载的过程.类加载器.ClassLoader.双亲委派机制.自定义类加载器等,这些都是博主自己的一点理解,如果有误,欢迎大家评论拍砖~ 关于JVM运行时数据区 JVM运行时数据区 关于类加载 class文件加载至内存,链接(校验.解析),初始化:最终形成JVM可以直接使用的JAVA类型的过程. 加载:在方法区形成类的运行时数据结构:在堆里面形成该类的Class对象,作为访问方法区的入口. 加载 链接:class文件是否存在问题:一

  • 一文读懂Jvm类加载机制

    前言 一个月没更新了,这个月发生了太多的事情,导致更新的频率大大降低,不管怎样收拾心情,技术的研究不能落下! jvm作为每个java程序猿必须了解的知识,博主推荐一本书<深入理解Java虚拟机>,以前博主在学校的时候看过几遍,每一次看都有新的理解.加上工作了也有一年多的时间了,有必要好好总结一番~ 什么是jvm 平常我们编写代码都是编写的.java文件,怎么部署到机器上运行呢?通过打jar包或者war包,然后部署运行. 如果看过jar包的内容那么就能知道,我们写的.java文件全部被编译成了.

  • JVM类加载机制原理及用法解析

    一.JVM 类加载机制 JVM 类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 1. 加载: 加载是类加载过程中的第一个阶段,这个阶段会在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的入口.注意这里不一定非得要从一个 Class 文件获取,这里既 可以从 ZIP 包中读取(比如从 jar 包和 war 包中读取),也可以在运行时计算生成(动态代理),也可以由其它文件生成(比如将 JSP 文件转换成对应的

随机推荐