JVM知识点梳理
JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。 JVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。
JVM 组成部分
如上面的架构图所示,JVM分为三个主要子系统:
- Class Loader子系统
- 运行时数据区
- 执行引擎
ClassLoader子系统
Java的动态类加载功能由ClassLoader子系统处理。它加载,链接。并在运行时(而非编译时)首次引用类似初始化类文件。
加载
类将由此组件加载。BootStrap ClassLoader,扩展ClassLoader和Application ClassLoader是有助于实现该目标的三个ClassLoader。
- BootStrap ClassLoader :负责从引导类路径中加载类,仅用于rt.jar。最高优先级将给予此加载程序。
- 扩展ClassLoader :负责加载ext文件夹(jre \ lib)内的类。
- Application ClassLoader :负责加载应用程序级别的类路径,提到的环境变量路径等。
连结
- 验证:字节码验证程序将验证生成的字节码是否正确,如果验证失败,我们将收到验证错误。
- 准备:将为所有静态变量分配内存并为其分配默认值。
- 解决:将所有符号内存引用替换为“方法区域”中的原始引用。
初始化
这是ClassLoading的最后阶段;在此,所有静态变量将被分配原始值,并且将执行静态块。
运行时数据区
运行时数据区分为五个主要部分:
1、方法区域 :所有类级别的数据(包括静态变量)都将存储在此处。每个JVM只有一个方法区域,它是共享资源。
2、堆区 :所有对象及其对应的实例变量和数组将存储在此处。每个JVM还有一个堆区。由于“方法”和“堆”区域共享多个线程的内存,因此存储的数据不是线程安全的。
3、堆栈区 :对于每个线程,将创建一个单独的运行时堆栈。对于每个方法调用,将在堆栈存储器中创建一个条目,称为堆栈帧。所有局部变量都将在堆栈存储器中创建。堆栈区域不是共享资源,因此是线程安全的。堆栈框架分为三个子实体:
- 局部变量数组——与该方法有关,涉及多少局部变量,并且相应的值将存储在此处。
- 操作数堆栈——如果需要执行任何中间操作,则操作数堆栈充当执行该操作的运行时工作区。
- 帧数据——与该方法相对应的所有符号都存储在此处。在任何例外情况下,捕获块信息将保留在帧数据中。
4、PC寄存器 :每个线程将具有单独的PC寄存器,以在执行指令后保存当前执行指令的地址,PC寄存器将用下一条指令进行更新。
5、本机方法堆栈 :本机方法堆栈保存本机方法信息。对于每个线程,将创建一个单独的本机方法堆栈。
执行引擎
分配给运行时数据区的字节码将由执行引擎执行。执行引擎读取字节码并逐段执行。
1、解释器:解释器解释字节码的速度较快,但执行速度较慢。解释器的缺点是,当多次调用一种方法时,每次都需要新的解释。
2、JIT编译器:JIT编译器消除了解释器的缺点。执行引擎将使用解释器的帮助来转换字节码,但是当发现重复的代码时,它将使用JIT编译器,该编译器将编译整个字节码并将其更改为本地代码。此本地代码将直接用于重复的方法调用,从而提高系统的性能。
- 中间代码生成器——产生中间代码
- 代码优化器——负责优化上面生成的中间代码
- 目标代码生成器——负责生成机器代码或本机代码
- Profiler——一个特殊的组件,负责查找热点,即是否多次调用该方法。
3、垃圾收集器:收集并删除未引用的对象。垃圾回收可以通过调用触发System.gc(),但不能保证执行。JVM的垃圾收集收集创建的对象。
相信看到这里,大家对多线程应该有了基本的认识,那接下来咱们一起来看相应的学习路线。
JVM学习路线
是不是感觉比较繁琐?不用担心,在这里小编早已经将清华大佬的学习秘籍帮大家整理好了,为了不影响大家的阅读体验,小编只是展示了一部分细节,有需要深度学习的朋友,请帮忙转发+关注小编,在私信回复【学习】即可免费领取哦~~~
第1章:Java虚拟机概述
本章简单介绍了Java语言产生的历史背景。Java语言所要解决的是如何能够不关注底层技术细节就能实现兼容性,詹爷给出的答案是使用中间语言,通过中间语言来实现跨平台兼容的目标。
章节简介
- 从机器语言到Java——詹爷, 你好
- 兼容的选择:一场生产力的革命
- 中间语言翻译
- 常见汇编指令
- JVM指令
第2章:Java执行引擎工作原理:方法调用
本章主要讲解了JVM内部的call stub 例程的定义和调用机制,但是并没有一开始便直入主题,主要是考虑到技术的难度太大,很多人理解不了。因此作者只能用心良苦地设计了很多C和汇编程序,从物理机器执行函数调用的机制开始讲起,为大家揭开物理机器在调用函数时设计的若干细节。
章节简介
- 方法调用
- 真实的机器调用
- C语言函数调用
- JVM的函数调用机制
- 函数指针
- CallStub函数指针定义
- _call_ stub_ _entry 例程
第3章:Java数据结构与面向对象
从程序的角度看,数据结构是若干数据的有机结合,一个数组、一个链表、一个堆栈都是数据集,这些数据在内存位置上有着紧密的联系,例如,对于数组而言,相邻的两个元素在内存位置上也是彼此相邻的;而对于链表,内存空间上未必彼此相连,但是相邻的两个元素中必定有一个元素保存着一个指针指向另一个元素的内存位置。而从人类的角度看,一个特定的数据结构可以更好地描述客观世界,例如通过一个Java类可以描述一只猫、一个手机,而通过类的组合则可以描述几乎任意复杂的事物。这便是数据结构的意义所在。
章节简介
- 从Java算法到数据结构
- 数据类型简史
- Java数据结构之偶然性
- Java类型识别
- 大端和小端的概念
- 大小端产生的本质原因
- 大小端验证
- 大端和小端产生的场景
- 如何解决字节序反转
- 大小端问题的避免
- JVM对字节码文件的大小端处理
第4章:Java字节码实战
本章以一个具体的Java程序为例,分析了其对应的字节码文件中的数据。可以发现,Java编译器在生成Javaclass字节码文件时,全是按套路出牌的,那么我们在分析时也按照套路走,便不难理解字节码文件的内容。
字节码文件中最重要的是Java方法所对应的字节码指令( 至少笔者这么认为), Java 源程序的逻辑都封装在字节码指令中。对字节码指令在字节码文件中的存储方式有了透彻的理解,便意味着你对JVM执行引擎入门了。
章节简介
- 字节码格式初探
- 魔数与版本
- 常量池的基本结构
- JVM所定义的11种常量
- 常量池元素的复合结构
- 常量池的结束位置
- 访问标识与继承信息
- 字段信息
- 方法信息
第5章:常量池解析
本章详细分析了解析Java字节码常量池的原理,描述了JVM内部常量池对象的内存分配机制,并由此阐述了JVM内部的对象表示机制——oop-klass 模型。想要研究JVM内核的道友应当认真阅读本章,最好能够非常熟悉常量池的内存分配机制,因为后续章节会讲解Java字段、方法的内存分配机制,而Java字段和方法的内存分配机制基本与常量池的内存分配机制类似,因此对常量池的内存分配机制理解得越透彻,则后续理解其他对象的内存分配机制便会越轻松。
章节简介
- 常量池内存分配总体链路.
- 内存分配
- 初始化内存
- oop-klass模型
- 常量池klass模型(1)
- 常量池klass模型(2)
- constantPoolOop域
- 初始化tag
- 解析常量池元素
第6章:类变量解析
总体而言,HotSpot 解析Java类变量的脉络比较清晰,但是也可以看出花了很多心思,这导致JVM虽然在执行引擎上相比于那些直接编译成本地机器码的编程语言可能要稍逊一筹, 但是在对象的内存分配上,并不比这些编程语言多浪费一点空间(除了每个Java类对象必须保留一个对象头),甚至由于字段重排的优化策略,对内存的利用率还要高于这些编程语言的编译器的分配算法。
章节简介
- 类变量解析
- 静态变量偏移量
- 非静态变量偏移量
- Java字段内存分配总结
- 字段重排与补白
- private字段可被继承吗
- 使用HSDB验证字段分配与继承
- 引用类型变量内存分配
第7章:Java栈帧
本章全面分析了Java方法栈帧创建的过程,机器指令几乎是逐个讲解的。然而,笔者在阅读JVM的这部分机制指令的过程中,不仅仅停留于分析机器指令本身的含义,还进行了更深入的思考,仔细推敲了每一条机器指令的背景,为何要这么实现,如果不这么实现有没有问题,相信真正有耐心读下来并且能够读懂的道友能够体会笔者的这种深人思考!
章节简介
- entry_ point 例程生成
- constMethod的内存布局
- 局部变量表空间计算
- 初始化局部变量区
- 栈帧是什么
- 硬件对堆栈的支持
- 栈帧开辟与回收
- 堆栈大小与多线程
- JVM栈帧与大小确定
- 栈帧创建
- 局部变量表
- 栈帧深度与slot复用
- 最大操作数栈与操作栈复用
第8章:类方法解析
本章主要描述了Java方法解析的技术实现。相比于前面章节所讲解的Java类字段的解析,Java类方法解析明显要复杂得多。这种复杂性体现在Java方法属性本身拥有众多信息,尤其是字节码指令部分。除了字节码指令,还有LVT、miranda 方法等,存储格式比较复杂,并且概念理解起来也并不是一-件轻松的事情。JVM为Java方法在内存中所构建的对等体也明显更加复杂。
同时,Java方法的解析还承担了一部分实现面向对象机制的责任,其核心技术便是vtable。只有真正理解了vtable 的实现机制,才能真正理解Java面向对象与多重继承的原理。
章节简介
- 方法签名解析与校验
- code属性解析.
- LVT&LVTT
- 创建methodOop
- Java方法属性复制
- <clinit>与<init>
- 查看运行时字节码指令
- C++中的多态与vtable
- Java中的多态实现机制
- vtable特点总结
- vtable机制逻辑验证
第9章:执行引擎
JVM最核心的技术便是执行引擎,最难的也是执行引擎。要想透彻理解JVM的执行引擎,就必须先理解物理计算机CPU执行运算的机制。本书详细描述了物理CPU进行取值、译码、运算的原理,并从这个点出发,逐步深入讲解JVM的执行引擎的运行机制。
章节简介
- 执行引擎概述
- 指令长度..
- JVM的两级取值机制
- 取指指令放在哪
- 程序计数器在哪里
- 译码
- 栈顶缓存
- 栈式指令集
- 操作数栈在哪里.
- 栈帧重叠
- entry_ point 例程机器指令
- 执行引擎实战
- 字节码指令实现
第10章:类的生命周期
类的加载机制与生命周期等概念,在各种书籍与各种网络博客里随处可见,然而对于一个想要真正了解其内部实现的人而言,那些都涉人过浅。本章“拨云见日”,从JVM源码的角度,还原出Java类加载的真实机制,以及类生命周期的实现方式。
章节简介
- 类的生命周期概述
- 类加载——镜像类与静态字段
- Java主类加载机制
- 类加载器的加载机制
- 反射加载机制
- import与new指令
- 类加载器的定义
- 系统类加载器与扩展类加载器创建
- 双亲委派机制与破坏
- 父加载器
- 预加载
- 引导类加载
- 栈.上分配与逃逸分析
- TLAB
- 指针碰撞与eden区分配
- 清零
- 偏向锁
- 压栈与取指
JVM涉及的知识面十分广阔,因此限于篇幅,本篇并未覆盖JVM的全部内容。总体而言,本篇重点描述了JVM从启动开始到完成函数执行的详细机制,读完本篇,相信你一定能够明白JVM执行Java程序的底层机制,能够明白JVM将Java语言一步步转换为CPU可执行的机器码的内部机制,以及为此而制定的各种规范的实现之道,例如oop-klass 模型、堆栈分配模型、类加载模型等。
实战是检验自己成果的重要方式
所谓实战,并不是让大家空造项目,在这里小编整理了2020最新阿里面试真题,如果换做是你,你又能和面试官过上几个回合呢?
- JDK、 JRE、JVM 的关系是什么?
- JVM 的内存模型以及分区情况和作用
- JVM 对象创建步骤流程是什么?
- 垃圾回收算法有几种类型? 他们对应的优缺点又是什么?
- 类的加载过程是什么?简单描述一下每个步骤
- JVM 预定义的类加载器有哪几种?分别什么作用?
- 什么是双亲委派模式?有什么作用?
- 介绍一下 JVM 中垃圾收集器有哪些? 他们特点分别是什么?
- 什么是 Class 文件? Class 文件主要的信息结构有哪些?
- 对象“对象已死” 是什么概念?
- Java 语言怎么实现跨平台的?
- 详细介绍一下对象在分带内存区域的分配过程?
- G1 与 CMS 两个垃圾收集器的对比
- 线上常用的 JVM 参数有哪些?
- 对象什么时候进入老年代?
- 什么是内存溢出, 内存泄露? 他们的区别是什么?
- 引起类加载操作的行为有哪些?
- 介绍一下 JVM 提供的常用工具
- 什么情况下会出现栈溢出
- 说一下强引用、软引用、弱引用、虚引用以及他们之间和 gc 的关系
如果是你,你能达到什么程度?
后记
学习是一个漫长的过程,只有耐得住寂寞,才能收获到成功的甘醇!!!
在这里,小编已经将此面试真题和前文的学习文档打包归类,有需要深度学习的朋友,请帮忙转发+关注小编,并私信回复【学习】即可哦~~~