【Java】JVM 知识串讲

article/2025/6/27 10:47:17

1. JVM 是什么

JVM 是 Java 虚拟机的简称,我们在下载 Java 运行环境时(jre),就已经包含了 JVM 了,JVM 是 Java实现跨平台的最核心的部分,所有的 Java 程序会首先被编译为 .class 的类文件,这种类文件可以在虚拟机上执行

2. JVM 的位置

JVM 是 Java 虚拟机的简称,其运行在操作系统之上

在这里插入图片描述

3. JVM 的体系结构

JVM 由类加载器、运行时数据区、执行引擎和本地方法接口组成。它们之间的关系如下图所示:
在这里插入图片描述

4. 类加载器

在这里插入图片描述

通过下列代码测试类加载器,输出结果如下,也证明了 JVM 共含三种类加载器 ,分别是: 应用类加载器 AppClassLoader 、扩展类加载器 ExtClassLoader 、根加载器 BootStrap(因为底层是用 C 写的,所以访问不到)

/*** @Author: WanqingLiu* @Date: 2023/02/06/9:49* 测试 Car 的类加载器*/
public class Car {public static void main(String[] args) {Car car = new Car();// 通过反射得到 Class 类Class Car = car.getClass();System.out.println(Car.getClassLoader()); // ” sun.misc.Launcher$AppClassLoader@18b4aac2 “System.out.println(Car.getClassLoader().getParent()); // ”sun.misc.Launcher$ExtClassLoader@4554617c“System.out.println(Car.getClassLoader().getParent().getParent()); // ”null“ —— ? 为什么输出是null : 因为底层是用 C 写的, Java 代码访问不到 ?}
}

5. 双亲委派机制

双亲委派机制是类加载器在工作时(加载类时)所要遵循的工作模型。双亲委派模型的工作流程是:如果一个类加载器收到了类加载的请求,它会把请求委托给父加载器去完成,直至类加载请求被传递到顶层的启动类加载器中。只有当父加载器在它的搜索范围中没有找到所需的类时,子加载器才会尝试自己去加载该类。

通过双亲委派机制 JVM 类加载器工作过程如下:

  1. 当 AppClassLoader 加载一个类时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给它的父类加载器 ExtClassLoader 去完成
  2. 当 ExtClassLoader 加载一个类时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给 BootStrap ClassLoader 去完成。
  3. 如果BootStrap ClassLoader加载失败,会使用 ExtClassLoader 来尝试加载;
  4. 若 ExtClassLoader 也加载失败,则会使用 AppClassLoader 来加载,如果 AppClassLoader 也加载失败,则会报出异常 ClassNotFoundException。

验证双亲委派机制,下面的代码不能正常允许:

package java.lang;
/*** @Author: WanqingLiu* @Date: 2023/02/06/10:19*/
public final class String {public static void main(String[] args) {System.out.println("我是自定义的 String 类");}
}

6. 沙箱机制

沙箱机制是 Java 安全模型的核心,沙箱就是一个限制程序运行的环境。沙箱机制就是将 Java 代码限定在 JVM 特定运行范围中,并且严格限制代码对本地资源的访问。( 沙箱机制的出现主要是因为 Java 当时想和其他语言竞争,所以得有比其他语言好的地方,因此就提出了沙箱机制)

经过 Java 多代的升级,沙箱机制演化为下图所示的 Demain 域的概念:
在这里插入图片描述

沙箱机制可以保证安全的原因:

  • 字节码校验器: 系统类防止内存中出现多份同样的字节码
  • 类装载器:采用双亲委派机制使得外层同名恶意类不得使用
  • 存储控制器:控制核心 API 对系统的操作权限,用户可自己指定
  • 安全管理器:核心 API 和操作系统间的主要接口,实现权限控制
  • 安全软件包:java.security 包下的类,允许用户自行定义安全特性

7. native 关键字

native 关键字修饰的方法表示本地方法,带了 native 关键字,Java 的作用范围就达不到了,表示需要调用底层 C 语言写的库

调用方式为 JVM 运行时数据区的本地方法栈 调用 JVM 提供的本地方法接口 JNI (Java Native Interface )

那从上面我们也可以看出,JNI 的作用为 扩展 Java 语言的使用,融合不同的编程语言为 Java 所用。 现在在企业应用中很少见 JNI 的使用,但是驱动硬件的时候很多见(比如: Java 驱动打印机)

以 Thread 类中的 start0 方法为例,理解 native 关键字 :

在这里插入图片描述

8. PC 寄存器

每个线程都有一个私有的程序计数器,其指向方法区中的方法字节码(即指向即将要执行的指令的执行代码),其是一个非常小的内存空间,几乎可以忽略不计

9. 方法区

在这里插入图片描述
方法区是 JVM 内存中的一种,其被所有线程所共享,方法区中保存静态变量、常量和类信息(如构造函数、接口代码)。

10. 栈

栈内存主管程序的运行,其生命周期和线程同步,线程结束,栈内存释放。因此,对于栈来说,不存在垃圾回收问题。
栈内存中存放 8大基本数据类型 、对象引用 和 实例的方法 等

用栈解释为什么 main 方法最后执行

如下图所示:因为 main 方法最先入栈,因此最后执行
在这里插入图片描述

栈运行实例的方法原理:通过 栈桢,如下图所示

在这里插入图片描述

栈溢出 StackOverError :递归时常出现的问题,因为方法一直入栈,不能出栈执行,造成了栈溢出

11. 三种 JVM

  • HotSpot —— 我们都是相对 HotSpot 说
  • JRockit
  • J9VM

12. 堆

堆 Heap,一个 JVM 只有一个堆内存,所有线程共享这一个堆内存。堆中存放所有对象的实例、类、方法、常量、变量等并保存所有引用类型的真实变量。

堆中详细区域分为如下:

  • 新生区: 包括伊甸园区、幸存者 0 区 和 幸存者 1 区
  • 养老区
  • 永久区 —— JDK 1.8 后改名为 元空间,其中含有 方法区,因此方法区也是堆的一部分

堆中内存分配如下图所示:
在这里插入图片描述

元空间(永久代)逻辑上存在,但是物理上不存在 —— 它属于堆,但是真实计算物理区域,只有新生代和老年代

通过如下代码进行测试:

/*** @Author: WanqingLiu* @Date: 2023/02/05/18:49* Xms 初始化内存分配大小* xmx 最大分配内存* -XX:+HeapDumpOnOutOfMemoryError* -XX:+PrintGCDetails*/
public class Demo01 {public static void main(String[] args) {// jvm 试图使用的最大内存 —— 默认的总内存是电脑内存的 1/4long max = Runtime.getRuntime().maxMemory();// jvm 的总内寸 —— 是最大内存的 1/64long total = Runtime.getRuntime().totalMemory();System.out.println("max = " + max + "字节\t" + max/(double)1024/1024  + "MB");System.out.println("total = " + total + "字节\t" + total/(double)1024/1024 + "MB");}
}

在这里插入图片描述

通过上述代码可得, 元空间只是逻辑上存在

13. 新生区、老年区

新生区 : 类诞生和成长的地方,甚至死亡

  • 伊甸园区:类诞生的地方,所有对象都是在伊甸园区 new 出来的
  • 幸存者区:分为 from 区 和 to 区,两者可交换,用于垃圾回收

14. 永久区

永久区是常驻内存的,存放 JDK 自带的 Class 对象,Interface 元数据 —— 即 java 运行时的一些环境或者类信息,这个区域不存在垃圾回收,关闭虚拟机时释放该区域内存

  • JDK 6 : 永久代,常量池在方法区中
  • JDK 7 :永久代,但是在退化,常量池在堆中
  • JDK 8 :无永久代,变为元空间,常量池在元空间

15. 堆内存调优

堆内存可能会出现 OOM 故障(即 Out Of Memory 错误,表示堆内存满了),这时我们就需要进行堆内存调优,快速定位出现错误的位置

当一个启动类加载大量第三方 Jar 或者 Tomcat 部署太多应用, 产生大量反射类,就可能会出现 OOM

解决:

  1. 调整 堆 内存空间,看结果

使用 IDEA 调整 堆内存大小方法如下:

加入 VM option 选项,填入 -Xms1024m -Xmx1024m -XX:+PrintGCDetails ,其中 -XX:+PrintGCDetails 表示打印垃圾回收过程

在这里插入图片描述

  1. 分析内存,看一下那些地方出现了问题

在项目中突然出现了 OOM 故障 , 调错方式:

  • 使用内存快照分析工具 —— MAT、JProfiler

使用内存快照分析工具可以让我们直接看到代码第几行出错 ——

IDEA 整合 JProfiler 方式为:

  1. IDEA 下载 JProfiler 插件 —— 下载好要重启
  2. 本机下载 -Xms1m -Xmx1m -XX:+HeapDumpOnOutOfMemoryError 客户端:https://www.ej-technologies.com/products/jprofiler/overview.html
  3. VM Options 加入如下选项 -Xms1m -Xmx1m -XX:+HeapDumpOnOutOfMemoryError, 表示拍摄内存快照
  4. 使用 JProfiler 客户端打开拍摄的快照,进行分析
  • Dedug , 一行行分析代码

16. GC —— 分代收集算法

垃圾回收在堆中,即 GC 的作用区域在堆中

JVM 进行 GC 的堆内存位置:

  • 新生代
  • 幸存区 (from to)—— from to 是交换的
  • 老年区

按照 GC 程度划分的 GC 两种类型

  • 轻 GC :即普通 GC
  • 重 GC:即全局 GC

16.1 引用计数法

在这里插入图片描述

16.2 复制算法

将 幸存者区,分为 from 区 和 to 区,遵循谁空谁是 to 区的原则,两者间可进行交换,复制算法执行过程为:

  1. 每次 GC 将 Eden 区存活的对象移动到幸存区中,一旦伊甸园区被 GC , 伊甸园区为空的
  2. 复制算法保证 to 区永远是空的 (复制方式为:每次将 GC 后存活的对象复制到 to 区,然后 to 区变为 from 区,将原 from 区清空,变为 to 区)
  3. 当一个对象经历了15次(可以调整)GC,就进入养老区

好处:没有内存碎片
缺点:浪费内存空间(多了一半 to 区永远是 null)

16.3 标记清除算法

在这里插入图片描述

缺点:两次扫描,严重浪费时间,而且会产生内存碎片(非连续的空间)
优点:不使用额外空间

16.4 标记压缩算法

在这里插入图片描述

在标记清除算法基础上再加一次扫描,向一端移动存活的对象,从而清除内存碎片
—— 优化:清除 n 次,压缩 1 次

总结 GC 算法:

内存效率 : 复制 > 标记清除 > 标志压缩
内存整齐度:复制算法 = 标记压缩 > 标记清除
内存利用率: 标记压缩 = 标记清除 > 复制算法

没有最好的算法,但是有针对与每个常见场景的最合适的算法

年轻代:存活率低, 使用复制算法
老年代:存活率高,区域大,使用标记清除加标记压缩混合实现 —— JVM 调优

17. JMM

Java Memory Medol

  1. 什么是 JMM: JMM 是一个抽象的概念,一个缓存一致性协议,其定义了读写的规则,
    JMM 定义了线程工作内存和主内存中的抽象关系,解决共享对象的可见性问题(volatile)
  2. JMM 的功能: 官方 博客 视频
  3. JMM 如何学习

最后:JVM 面试题

  1. JVM 的内存模型和分区 - 详细到每个区放什么
  2. 堆里面的分区有那些, Eden、 from 、to 、老年区的特点
  3. GC 算法 用法和原理
  4. 轻 GC 和 重 GC 分别在什么情况下发生
  5. 谈谈你对 JVM 的理解 ? Java 8 虚拟机和之前的变化
  6. 什么是 OOM,什么是栈溢出,怎么分析
  7. JVM 的常用调优参数
  8. 内存快照如何抓取,怎么分析 Dump 文件
  9. 堆 JVM 类加载器的认识

http://chatgpt.dhexx.cn/article/0aRVIeGg.shtml

相关文章

视频理解论文串讲——学习笔记

文章目录 DeepVideoTwo-StreamBeyond-short-SmippetsConvolutional FusionTSN C3DI3DNon-localR(21)DSlowFast Timesformer 本文是对视频理解领域论文串讲的笔记记录。 一篇相关综述:Yi Zhu, Xinyu Li, Chunhui Liu, Mohammadreza Zolfaghari…

CGB2202串讲-java复习

java基础: day01: 1:java的开发环境: 编译器:.java源文件,编译成.class的字节码文件 运行期:jvm加载并运行.class字节码文件 2:名词解释: jvm: 加载并运行.cl…

我的论文串讲「一」

文章目录 [Done]2022-arXiv-It’s DONE Direct ONE-shot learning without training optimizationAbstractIntroductionRelated workMethodologyImplementation and DatasetResults and Discussion [Phase]2021-SPIE-Deep neural networks to improve the dynamic range of Zer…

多模态串讲(上)

多模态的学习在最近几年异常火爆,除了普通的多模态学习,比如视觉问答,图文检索等,其实之前讲的所有这种Language Guided Detection,或者Language Guided Segmentation,这些任务都是多模态的,还有最近火的文…

C++【引用】——串讲

【引用】——串讲(视频89-94) Note: i.视频为黑马程序员C视频,系列文章为视频听课笔记; ii.引用不仅包含定义及简单应用,在类与对象…中也有涉及; iii.难度指数: iv.不论变量、函数名、标识符形式怎样复杂…

CLIP 改进工作串讲(下)

CLIP 改进工作串讲(下) 本文为 CLIP 改进工作串讲(下)【论文精读】 的学习笔记。 图像生成 最近一年图像生成领域扩散模型大火,尤其是文本生成图像,DALL-E、imagen 等工作层出不穷,有机会专门…

操作系统串讲

前言 文章内容来源:东北大学的操作系统MOOC视频在操作系统的不同阶段,计算机的工作形式也不同,不要在一开始就将操作系统在心里预设成现代的 windows 或 linux 操作系统,以及将计算机预设成个人电脑等,防止代错对象、…

4.7串讲

4.7串讲 Java基础API 文章目录 4.7串讲 Java基础API字符串字符字符串StringBulider,StringBuffer 内存结构正则表达式字符字符类预定义字符类POSIX字符类(仅US-ASCII)java.lang.Character 类(简单的 java 字符类型)Uni…

计算机网络知识串讲复习(超全)

本篇我总结了学习计算机网络时必备的知识,可以用于巩固知识或者期末复习~~~如果觉得博主爆肝总结的不错,感谢点赞! 目录 1、计算机网络的几个发展阶段 2、计算机网络的组成 3、协议的概念 4、实体,协议,服务,和服务访问点 5、计算机网络的分类 6、…

CLIP改进工作串讲(上)

CLIP改进工作串讲(上) 本文为 CLIP 改进工作串讲(上)【论文精读】 的学习笔记。 CLIP 改进方向 语义分割 Lseg、GroupViT 目标检测 ViLD、GLIP v1/v2 视频理解 VideoCLIP、CLIP4clip、ActionCLIP 图像生成 VQGAN-CLIP、CLIPass…

毕业知识串讲

1. 京淘后端项目架构 1.1 数据库主从同步 1.1.1 业务需求说明 当数据库发生宕机的现象,如果配置了数据库主从同步,则可以从从库中获取现有记录,显示数据的恢复. 1.2 数据库主从同步原理 1.2.1 数据库冷备份 说明: 人工的将数据库文件定期导出,一式三份 如果其中一份丢失…

如何做好技术串讲

首先,如何做好演讲是个好话题,不过这过于大众的主题不想写,除非哪天能想到点 新意 再说; 其次,串讲和演讲有啥区别呢?其实也没啥区别,一会儿说说我自己的理解; 最后,什么…

软件开发过程与项目管理(8.软件项目质量计划)

软件开发过程与项目管理(8.软件项目质量计划) 课件 软件质量基本概念 质量定义 质量是满足要求的程度,包括符合规定的要求和满足顾客隐含需求。 软件质量定义 软件质量是软件满足明确说明或者隐含的需求的程度 质量与等级 质量与等级…

软件项目开发基本流程详解

软件项目开发流程图是用来详细描述了软件在开发过程中产品调研、设计、开发、测试等各个阶段中各个角色,包含产品经理、研发、测试、用户等需要处理的事情,以及在不同阶段可以达到哪种效果。那么,一款软件从研发到发布到底要经过哪些流程呢?…

嵌入式软件开发流程

根据使用的开发工具套件不同,软件开发流程会有差异,但主要步骤大致相同。对于使用宿主机(PC)的集成化开发环境,软件开发流程一般包括创建项目、添加文件、编译连接、下载调试等步骤,如下图所示。 图1&#…

软件项目开发流程以及人员职责,软件工程中五种常用的软件开发模型整理

文章目录 一、软件项目开发流程逻辑图开发流程需求分析概要设计详细设计编码测试软件交付验收维护 软件维护软件升级 软件项目开发流程以及人员职责软件工程中五种常用的软件开发模型整理软件系统开发流程七大详细步骤完整介绍 一、软件项目开发流程逻辑图 这张图应该清楚的说…

软件工程项目流程

软件工程项目流程 1.1 项目合作与成员 根据本项目的工作内容和范围,我们将成立一个20人左右的项目工作组来负责本项目的开发。 1.2 项目实施方法 项目管理的成效直接关系到整个项目的成败。尤其是实施与移动互联网有关的新技术应用项目,无论在国内和国外都是有一定难度的,更…

软件工程----开发大致流程

软件开发的流程 需求分析概要设计项目计划详细设计编码测试项目测试项目部署后期运维软件开发注意事项 不同的软件项目,有不同的需求侧重点,开发流程也是不一样的。比如开发一个大型Web电商项目,这个往往需要采用前后端分离的方式&#xff0c…

软件项目开发流程逻辑图

相关链接: 软件项目规划大纲知识点

软件项目的开发流程

一个项目的开发流程 软件开发流程(Software development process) 1.项目启动 1、项目组成立(公司成员、客户成员) 2、制定项目预期目标 3、制定项目计划周期 4、建立好项目组成员沟通机制 2.需求调研 1、创建调研计划、协调调研时间 2、收集客户资料,获取客户需求 …