大白话谈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内存结构 JVM的类加载机制
JVM内存结构: 1.java虚拟机栈:存放的是对象的引用(指针)和局部变量 2.程序计数器:每个线程都有一个程序计数器,跟踪代码运行到哪个位置了 3.堆:对象.数组 4.方法区:字节流(字节码文件) ...
- JVM之类加载机制
JVM之类加载机制 JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 类加载五部分 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这 ...
- JVM的类加载机制全面解析
什么是类加载机制 JVM把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被JVM直接使用的Java类型,这就是JVM的类加载机制. 如果你对Class文件的结 ...
- 一文教你读懂JVM的类加载机制
Java运行程序又被称为WORA(Write Once Run Anywhere,在任何地方运行只需写入一次),意味着我们程序员小哥哥可以在任何一个系统上开发Java程序,但是却可以在所有系统上畅通运 ...
- 漫谈JVM之类加载机制(篇一)
前言 最近在看一本书,发现代码里用到了Thread.currentThread().getContextClassLoader(),为什么类加载器还与线程有关系呢,为什么不直接使用ClassLoade ...
- JVM的类加载机制
虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 类加载的过程: 包括加载.链接(含验证.准备 ...
- 【JVM】类加载机制
原文:[深入Java虚拟机]之四:类加载机制 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载.验证.准备.解析.初始化.使用和卸载七个阶段.它们开始的顺序如下图所示: 类加 ...
- 深入理解JVM(3)——类加载机制
1.类加载时机 类的整个生命周期包括了:加载( Loading ).验证( Verification ).准备( Preparation ).解析( Resolution ).初始化( Initial ...
- (转) JVM——Java类加载机制总结
背景:对java类的加载机制,一直都是模糊的理解,这篇文章看下来清晰易懂. 转载:http://blog.csdn.net/seu_calvin/article/details/52301541 1. ...
随机推荐
- Discovering Reinforcement Learning Algorithms
郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! arXiv:2007.08794v1 [cs.LG] 17 Jul 2020 Abstract 强化学习(RL)算法根据经过多年研究手动发 ...
- latex:公式的序号
1.排序单位 在文类book或report中,行间公式是以章为排序单位的,即每一新章节开始,公式序号计数器equation就被清零.比如第1章第3个公式的序号是(1.3),第2章第1个公式的序号是(2 ...
- 实用教程!SPSSAU验证性因子分析思路总结
验证性因子分析,是用于测量因子与测量项(量表题项)之间的对应关系是否与研究者预测保持一致的一种研究方法.尽管因子分析适合任何学科使用,但以社会科学居多. 目前有很多软件都可以非常便利地实现验证性因子分 ...
- muduo源码解析8-date类
date class date:copyable { }: 作用: 此类作用主要是实现年月日和julianDay的互相转换内部最重要的一个数据成员m_julianDayNumber在mymuduo:: ...
- Hadoop 2.6.1 集群安装配置教程
集群环境: 192.168.56.10 master 192.168.56.11 slave1 192.168.56.12 slave2 下载安装包/拷贝安装包 # 存放路径: cd /usr/loc ...
- Java面试题(异常篇)
异常 74.throw 和 throws 的区别? throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理.而throw则是指 ...
- [CSP-S2019]括号树 题解
CSP-S2 2019 D1T2 刚开考的时候先大概浏览了一遍题目,闻到一股浓浓的stack气息 调了差不多1h才调完,加上T1用了1.5h+ 然而T3还是没写出来,滚粗 思路分析 很容易想到的常规操 ...
- TinkPHP框架开发的CRMEB小程序商城v4.0二次开发集成支付宝支付
前言 大家都知道支付宝支付和微信支付宝都只能局限在自己的平台,微信内支付宝支付是根本就不能使用,即使是公众号支付也需要跳转到外部浏览器才可以唤起支付宝支付,并且QQ浏览器唤起支付宝支付还是问题很多,所 ...
- Android开发必有功能,更新版本提示,检测是否有新版本更新。下载完成后进行安装。
作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985,转载请说明出处. 给大家介绍个东西,MarkDown真的超级超级好用.哈哈.好了, 正题内容如下: 先 ...
- 【接口自动化】selenium库也有大用场(获取cookie)
相信有些童鞋在做接口.或者说接口自动化测试的过程中会遇到这样的场景:测试的接口,必须是需要登录后才能发起请求成功的. 那么怎么解决呢? 本着团队协作的精神,我们就去让开发同学开个后门,给你个" ...