类加载子系统

类文件首先需要经过类加载子系统,进行加载,进类信息等加载到运行时数据区,生成Klass的实例。

在类加载子系统中有以下3个阶段操作(广义上的加载):

  • 加载阶段

    • Bootstrap ClassLoader:引导类加载器,主要加载JDK里面的核心类
    • Extension ClassLoader:拓展类加载器
    • Application ClassLoader:应用加载器
  • 链接阶段
    • 验证
    • 链接
    • 解析
  • 初始化阶段



如果加载的时候失败了,则不会执行后面的链接等操作。

类加载子系统的作用:

  • 类加载器子系统可以从本地文件或者网络中加载Class文件,Class文件开头有特定标识“CAFEBABY”(魔数)。
  • 类加载器只负责将文件加载到运行时数据区,但是否可以运行,是执行引擎管的
  • 加载的类信息存放在方法区中,除了类信息以外,方法区还存放了运行时产量池信息,可能HIA包括字符串字面量和数字常量(这部分常量是Class文件中常量池部分的内存映射)。

譬如反编译后,会产生常量信息,里面包括常量以及符号引用等:

类加载器ClassLoader的角色,以下面的People.class为例:

通过类信息实例,可以通过new 实例化对象,也可以通过getClassLoader()获取类加载器,也可以通过实例getClass()获取类信息实例。

  1. People.class 存在本地硬盘上,相当于一个模板,最终可以实例化出n个同一个类但是属性不同的实例。
  2. People.class加载到JVM中,被称为DNA元数据模板,存放在方法区,也就是类信息。类信息也是对象。
  3. 从.class文件,到加载到JVM中,称为元数据模板,这个过程需要一个转换工具,这个工具就是类加载器(Class Loader)。

加载(Loading)

此处的加载,指的是类加载过程中的第一个阶段(环节),主要工作包括:

  • 1.通过类的全限定名获取定义此类的二进制字节流。
  • 2.将这个二进制字节流所代表的静态存储结构转化为方法区(JDK7以及之前叫永久代,JDK8之后成为元空间)的运行时数据结构。
  • 3.在内存中生成一个该类的java.lang.Class对象,作为方法区该类的各种数据的访问入口,也就是类信息对象。

类的.class文件来源方式包括以下:

  • 本地系统直接加载
  • 网络传输获取
  • 从zip压缩包读取
  • 运行的时候计算生成,譬如动态代理技术
  • 由其他文件生成,譬如场景:JSP
  • 从加密文件中解密获得

链接

链接阶段又分为3个阶段:

  • 验证:

    • 目的是校验安全和法,确保Class文件的字节流中包含信息符合当前虚拟机要求,保证加载的类的正确性,不会危害到虚拟机的安全。
    • 主要包括4种验证:
      • 文件格式验证(譬如文件开头是"CAFEBABY")
      • 元数据验证
      • 字节码验证
      • 符号引用验证
  • 准备:
    • 为类变量(static)分配内存并且设置该变量的默认初始值,即零值
    • 不包含final修饰的static,因为final在编译的时候已经分配了,准备阶段会显示初始化。
    • 不会为实例变量分配初始化,类变量会分配在方法区,但是实例变量是跟随对象一起分配在Java堆里面(一般情况)
  • 解析:
    • 将常量池的符号引用转化成为直接引用的过程
    • 事实上,解析操作往往会伴随JVM在执行完初始化之后再执行
    • 符号引用就是一组符号来描述所引用的目标,《Java虚拟机规范》的Class文件格式中,直接引用就是直接指向目标的指针,相对偏移量或者一个间接定位到目标的句柄。
    • 解析这个阶段,主要是针对类或者接口,字段,类方法,接口方法,方法类型等等,对应的常量池中的CONSTANT_Class_info,CONSTANT_Fieldred_info,CONSTANT_Methodref_info等。

初始化

初始化,就是执行类的构造器<clinit>()的过程,注意<clinit>()是类的构造器,不是对象的。<clinit>()是初始化类的,就是把类装到JVM里的初始化,不是运行时对象的初始化。

<clinit>()这个方法不需要显式定义,而是javac编译器自动收集类中的所有变量的赋值动作,加上静态代码块,合并成的一个方法。

<clinit>()中代码的顺序和我们在类文件写的顺序一致。

执行子类的<clinit>()方法之前,JVM会保证先执行其父类的<clinit>(),默认父类是Object

仔细观察上面的代码,会发现,final的属性,即使是static修饰的,在<clinit>()里面都不会存在,这是为什么呢?

这是因为final修饰的是常量,常量不会在初始化的时候执行赋值!!!常量在编译的时候已经分配了,准备阶段会显示初始化。

如果我们将final去掉,就可以发现,去掉final修饰,字节码就会加上该字段的赋值:(下面的ldc是指常量池的意思,从常量池编号为#6的地方,加载该常量)

虚拟机在初始化的时候,已经保证了类的<clinit>()方法,即使在多线程的环境下,也只会执行一次,其底层的逻辑就是默认同步加锁了。

【作者简介】

秦怀,公众号【秦怀杂货店】作者,技术之路不在一时,山高水长,纵使缓慢,驰而不息。个人写作方向:Java源码解析,JDBC,Mybatis,Spring,redis,分布式,剑指Offer,LeetCode等,认真写好每一篇文章,不喜欢标题党,不喜欢花里胡哨,大多写系列文章,不能保证我写的都完全正确,但是我保证所写的均经过实践或者查找资料。遗漏或者错误之处,还望指正。

2020年我写了什么?

开源刷题笔记

平日时间宝贵,只能使用晚上以及周末时间学习写作,关注我,我们一起成长吧~

JVM笔记 -- 来,教你类加载子系统的更多相关文章

  1. JVM解毒——类加载子系统

    带着问题,尤其是面试问题的学习才是最高效的.加油,奥利给! 点赞+收藏 就学会系列,文章收录在 GitHub JavaEgg ,N线互联网开发必备技能兵器谱 直击面试 看你简历写得熟悉JVM,那你说说 ...

  2. 【JVM之内存与垃圾回收篇】类加载子系统

    类加载子系统 概述 完整图如下: 如果自己想手写一个 Java 虚拟机的话,主要考虑哪些结构呢? 类加载器 执行引擎 类加载器子系统作用 类加载器子系统负责从文件系统或者网络中加载 Class 文件, ...

  3. JVM上篇:类加载子系统

    JVM类加载 目录 JVM类加载 1.内存结构概述 2.类加载子系统概述 3.类的加载过程 2.1加载 2.2Linking 2.2.1验证(Verify) 2.2.2准备(Prepare) 2.2. ...

  4. JVM笔记--如果你写JVM,最需要考虑的重要结构是什么?

    开局一张图,前面已经从每一部分解析过JVM的内存结构了,现在按照顺序来分析: 整体上来看:类文件从类加载子系统,加载完成之后,主要存放在方法区(JRockit和H9没有方法区,这里指的是HotSpot ...

  5. JVM_02 类加载子系统

    JVM细节版架构图 本文针对Class Loader SubSystem这一块展开讲解类加载子系统的工作流程 类加载子系统作用 1.类加载子系统负责从文件系统或者网络中加载class文件,class文 ...

  6. JVM笔记五-堆区

    JVM笔记五-堆区 在JVM中,堆区是重中之重.通过前面文章的学习,我们知道了,栈区是不会有垃圾回收的,所以,经常说的垃圾回收,其实就是回收的是堆区的数据.在这里,我们将会看到传说中的,新生代.老年代 ...

  7. JVM2 类加载子系统

    目录 类加载子系统 类加载器子系统 类加载器ClassLoader角色 类加载的过程 案例 加载Loading 连接Linking 初始化Intialization clinit() 类的加载器 虚拟 ...

  8. JVM专题1: 类和类加载机制

    合集目录 JVM专题1: 类和类加载机制 Java对象的结构 在HotSpot虚拟机中, 对象在内存中存储的布局可以分为3块区域 对象头Header 实例数据Instance Data 对齐填充Pad ...

  9. 《Java编程思想》学习笔记(二)——类加载及执行顺序

    <Java编程思想>学习笔记(二)--类加载及执行顺序 (这是很久之前写的,保存在印象笔记上,今天写在博客上.) 今天看Java编程思想,看到这样一道代码 //: OrderOfIniti ...

随机推荐

  1. js optional chaining operator

    js optional chaining operator js 可选链 可选链操作符( ?. )允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效. ?. 操作符的功能类似于 ...

  2. TypeScript Generics All In one

    TypeScript Generics All In one TypeScript 泛型 代码逻辑复用 扩展性 设计模式 方法覆写, 直接覆盖 方法重载,参数个数或参数类型不同 test " ...

  3. 浏览器缓存 All In One

    浏览器缓存 All In One HTTP 缓存 强缓存 expired Cache-Control max-age s-maxage 协商缓存 E-tag last-modified 本地缓存 co ...

  4. i18n 和 L10n (internationalization and localization) 国际化与本地化(具有全球战略眼光的公司企业的必由之路)

    i18n 和 L10n (internationalization and localization)  国际化与本地化(具有全球战略眼光的公司企业的必由之路) 1 1 https://zh.wiki ...

  5. Android Jetpack All In One

    Android Jetpack All In One 在2018年,我们推出了Android Jetpack作为一组库,以帮助开发人员遵循最佳实践,减少样板代码以及编写可在Android版本和设备之间 ...

  6. Kotlin 入门教程

    Kotlin 入门教程 Android / Java https://developer.android.com/kotlin?hl=zh-cn 使用 Kotlin 开发 Android 应用 使用 ...

  7. Docker In Action

    Docker In Action Docker 实战 https://docs.docker.com/get-started/overview/ Docker Engine Docker Archit ...

  8. Cocos Creator 游戏开发

    Cocos Creator 游戏开发 https://www.cocos.com/products#CocosCreator 一体化编辑器: 包含了一体化.可扩展的编辑器,简化了资源管理.游戏调试和预 ...

  9. Python爬虫_百度贴吧(title、url、image_url)

    本爬虫以百度贴吧为例,爬取某个贴吧的[所有发言]以及对应发言详情中的[图片链接] 涉及: request 发送请求获取响应 html 取消注释 通过xpath提取数据 数据保存 思路: 由于各贴吧发言 ...

  10. JVM系列(四):java方法的查找过程实现

    经过前面几章的简单介绍,我们已经大致了解了jvm的启动框架和执行流程了.不过,这些都是些无关痛痒的问题,几行文字描述一下即可. 所以,今天我们从另一个角度来讲解jvm的一些东西,以便可以更多一点认知. ...