简单了解 JVM

 

目录

 

♫什么是JVM

 ♫JVM的运行流程

 ♫JVM运行时数据区

♪虚拟机栈

♪本地方法栈

♪堆

♪程序计数器

♪方法区/元数据区

 

♫类加载的过程

 

♫双亲委派模型

  ♫垃圾回收机制


♫什么是JVM

JVM 是 Java Virtual Machine 的简称,意为 Java虚拟机。 虚拟机是指通过软件模拟的具有完整硬件功能的、运行在一个完全隔离的环境中的完整计算机系统(如:JVM、VMwave、Virtual Box)。  JVM 和其他两个虚拟机的区别是: VMwave与VirtualBox是通过软件模拟物理CPU的指令集,物理系统中会有很多的寄存器,而 JVM则是通过软件模拟Java字节码的指令集,JVM中只是主要保留了PC寄存器,其他的寄存器都进行了裁剪。 

 ♫JVM的运行流程

JVM 是 Java 运行的基础,也是实现一次编译到处执行的关键,那么 JVM 是如何执行的呢?

我们知道程序在执行之前先要把java代码转换成字节码(class文件),而 JVM 首先需要把字节码通过类加载器(ClassLoader)把文件加载到内存中的运行时数据区(Runtime Data Area) ,而字节码文件是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine)将字节码翻译成底层系统指令再交由CPU去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能,这就是这4个主要组成部分的职责与功能。

 ♫JVM运行时数据区

从上图我们可以发现运行时数据区划分成5个部分,接下来我们就来看看他的内存布局。

♪虚拟机栈

虚拟机栈是给 Java 代码使用的栈,每个线程都会有一个,虚拟机栈描述的是 Java 方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息:

①. 局部变量表: 存放了编译器可知的各种基本数据类型(8大基本数据类型)、对象引用。局部变量表 所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量空间是完全确定的,在执行期间不会改变局部变量表大小。简单来说就是存放方法参数和局部变量。

②. 操作栈:每个方法会生成一个先进后出的操作栈。

③. 动态链接:指向运行时常量池的方法引用。

④. 方法返回地址:PC 寄存器的地址。

♪本地方法栈

Native Method Stack 中 Native 就表示 JVM 内部 C++ 写的代码,就是给调用 Native 方法( JVM 内部的方法)准备的栈空间。

♪堆

整个 JVM 中最大的区域,所有 new 出来的对象(类的普通成员变量)都是在堆上。

♪程序计数器

程序计数器是一块比较小的内存空间,记录当前线程执行到哪个指令,可以看做是当前线程所执行的字节码的行号指示器。 如果当前线程正在执行的是一个 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是一个 Native 方法,这个计数器值为空。

♪方法区/元数据区

元数据区是用来存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据的。

注:虚拟机栈、本地方法栈、程序计数器都是线程私有的(一个线程有一个),堆、元数据区是线程公有的(一个进程里的所有线程共用一个)。

 

♫类加载的过程

Java类加载是将 .class 文件中的二进制数据读入到内存中,并对数据进行校验、解析和初始化的过程类加载来说总共分为以下几个步骤:

♩. 加载:把 .class 文件找到,读取文件内容

♩. 连接:

        ①. 验证:根据 JVM 规范,检查 .class 文件是否符合规范

        ②. 准备:给类对象分配内存空间,设置初始值(基本数据类型设为为 0,引用数据类型设为 null

        ③. 解析:将常量池内的符号引用替换为直接引用的过程,也就是初始化常量的过程。(字符串常量有一块内存空间存字符串的实际内容,还有一个引用保存这块空间的起始地址,类加载前字符串常量存储在 .class 文件中(还没有内存地址),此时这个引用记录的是字符串常量在文件中的”偏移量“(符号引用),在类加载后字符串常量才放到内存里(有了内存地址),才会将”偏移量“替换成内存地址(直接引用))

♩. 初始化:

真正对类对象里的内容进行加载,加载父类、执行静态代码块

注:java 程序运行后不会把所有类一次性都加载,而是需要用到哪个再加载哪个

 

♫双亲委派模型

类加载描述的是找到 .class 文件读取内容的过程,而双亲委派模型描述的就是加载、找 .class文件的基本过程。了解双亲委派模型前,我们得先了解下 JVM 默认提供的三种类加载器:♩. BootstrapClassLoader负责加载标准库中的类(java 规范要求提供的类,无论哪种 JVM 都会提供)

♩. ExtensionClassLoader负责加载 JVM 扩展库中的类(规范之外,由 JVM 厂商提供的扩展功能)

♩. ApplicationClassLoader负责加载用户提供的第三方库/用户项目代码中的类 

这三个加载器彼此存在“父子类”的关系, BootstrapClassLoader 相当于 ExtensionClassLoder 的父加载器,ExtensionClassLoder 相当于 ApplicationClassLoder的父加载器。

双亲委派模型就是单加载一个类时,首先从 ApplicationClassLoader 开始,但 ApplicationClassLoader 会把加载任务交给父加载器 ExtensionClassLoader , ExtensionClassLoader 又会把加载任务交给父加载器 BootstrapClassLoader ,BootstrapClassLoader 没有父加载器才开始搜索标准库目录的类,找到了就加载,没找到就交给子加载器 ExtensionClassLoader,ExtensionClassLoader 搜索扩展库的目录,找到了就加载,没找到就交给子加载器 ApplicationClassLoader,ApplicationClassLoader 搜索用户项目相关目录,找到了就加载,没找到就抛出异常。

注:双亲委派模型的加载顺序确保了 BootstrapClassLoader 先加载,ApplicationClassLoader 后加载,可以避免因用户自己写的类导致 JVM 已有代码的混乱。

  ♫垃圾回收机制

垃圾回收机制即 GC 主要是对堆进行释放的,是以对象为单位进行回收的,因此也叫死亡对象的回收。

要想回收垃圾,首先得判断谁是垃圾,常见的判断是否为垃圾的方法有两种:

♩.引用计数

给每个对象都分配一个计数器,有引用指向它,计数器加一;有指向它的引用销毁,计数器减一。

显然这个方法简单有效,但还是存在缺点:内存浪费的多且可能存在循环引用(a 对象的属性指向 b,b 对象的属性指向 a,当 a 和 b 销毁时,a 和 b 的引用计数仍为 1)的问题。

♩.可达性分析

java 里的对象都是通过引用指向来访问的,通过遍历所有对象的引用指向就可以判断出某个对象可达不可达,java 的做法就是通过可达性分析。

确认了哪个对象是垃圾就可以对垃圾进行回收,常见的回收垃圾的做法有:

♩.标记清除

基本概念:标记清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。在标记阶段,它从根节点开始遍历,标记所有可达的对象。未被标记的对象被视为垃圾,这些对象在清除阶段被回收。


优点:标记清除算法实现简单,不需要移动存活对象。
缺点:标记清除算法执行效率较低,且清除后容易产生大量不连续的内存碎片,这可能导致后续对象分配时找不到足够的连续内存空间而提前触发垃圾回收。

♩.复制算法

基本概念:复制算法将内存分为两块,每次只使用其中一块。当一块内存用完时,将还存活的对象复制到另一块上,然后清理掉已使用的内存。

优点:由于只处理其中一块内存区域,复制算法运行速度较快,且不会产生内存碎片。

缺点:复制算法需要两倍的内存空间,代价较高。同时,如果对象的生命周期较长,这种复制操作会导致效率低下。

♩.标记整理

基本概念:标记整理算法结合了标记清除和复制算法的优点。在标记阶段后,将所有存活对象压缩到内存的一端,然后清理边界以外的内存。


优点:标记整理算法避免了标记清除算法的碎片问题,也不需要复制算法那么多的内存空间。
缺点:标记整理算法实现较为复杂,且移动对象的过程会产生额外的开销。

♩.分代回收

基本概念:分代收集算法基于这样一个事实:大部分对象会在年轻时死亡。它将堆内存分为新生代和老年代,不同年代采用不同的回收算法。新 new 出来的对象在伊甸区,熬过一轮 GC 就通过复制算法来到了幸存区,幸存也要经过周期性的 GC 考验,如果通过考验就进入另一个幸存区,没通过就释放掉,当一个对象在两个幸存区来回拷贝很多次了后就进入老年区,老年区偶而也要经历 GC 的考验,如果没通过就通过标记整理算法释放掉。


优点:分代收集算法通过将内存分区,可以更高效地回收垃圾,特别是针对新生代中大量短命的对象。
缺点:分代收集算法设计相对复杂,需要根据不同代的特点选择合适的回收算法。

注:JVM 就是基于分代回收算法回收垃圾的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/875641.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WPF DataGrid 列表中,DataGrid.Columns 列根据不同的值显示不同内容

需求&#xff1a;在WPF DataGrid 控件中&#xff0c;有以下列&#xff0c;绑定了一个LogType&#xff0c;值分别是0,1,2&#xff0c;根据不同的值&#xff0c;显示不同的内容以及背景 <DataGrid ItemsSource"{Binding EventLog}"><DataGrid.Columns><…

代码管理工具——git及阿里云云效的使用(包含git的使用及云效自动化部署)

1、做项目开发时都会用到代码管理工具,像是我之前使用过gitHub,Visual Studio等一些代码管理工具&#xff0c;这里介绍的是阿里云云效的使用。 2、首先登录阿里云云效&#xff0c;登录进去之后会看到公司给你开放的一个仓库。 3、进入仓库&#xff0c;点击克隆/下载&#xff0…

Google大数据架构技术栈

数据存储层 Colossus Colossus作为Google下一代GFS&#xff08;Google File System&#xff09;。 GFS本身存在一些不足 单主瓶颈 GFS 依赖单个主节点进行元数据管理&#xff0c;随着数据量和访问请求的增长&#xff0c;出现了可扩展性瓶颈。想象一下&#xff0c;只有一位…

网红酒店|基于java的网红酒店预定系统(源码+数据库+文档)

酒店预定|网红酒店|网红酒店预定系统 目录 基于java的网红酒店预定系统 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&am…

R语言统计分析——功效分析(比例、卡方检验)

参考资料&#xff1a;R语言实战【第2版】 1、比例检验 当比较两个比例时&#xff0c;可使用pwr.2p.test()函数进行功效分析。格式为&#xff1a; pwr.2p.test(h, n, sig.level, power, alternative) 其中&#xff0c;h是效应值&#xff0c;n是各相同的样本量。效应值h的定义如…

智能头盔语音识别声控芯片,AI离线语音识别ic方案,NRK3301

头盔是交通事故中保护电动车车主安全的最后一道屏障。为了增加骑行用户的安全保护&#xff0c;改善骑行用户的出行体验&#xff0c;让用户从被动使用头盔到主动佩戴头盔&#xff0c;头盔厂家与九芯电子合作&#xff0c;推出了语音智能头盔&#xff0c;它具备首家骑行专用的智能…

C++核心编程和桌面应用开发 第三天(C和C++的封装)

目录 1.封装 1.1C语言封装缺陷 1.2C下的封装 1.3封装的访问权限 2.C中struct和class的区别&#xff1a; 1.封装 1.1C语言封装缺陷 1.2C下的封装 优点1&#xff1a;将属性和行为作为整体&#xff0c;表现生活中的事务 优点2&#xff1a;将属性和行为加以访问权限控制 1…

vue的路由

v2用3版本&#xff0c;v3用4版本 import Vue from vue import VueRouter from vue-router Vue.use(VueRouter) const routes [] const router new VueRouter({ routes }) export default router import Vue from vue import App from ./App.vue import router from /router V…

kkFileView PDF Image Mode Preview BUG

kkFileView PDF & Image Mode Preview BUG lazyload.js officePicture.ftl pdf.ftl kkFileView getCorsFile?urlPath 会触发SSRF漏洞 kkFileView SSRF-CSDN博客 commonHeader.ftl initWaterMark() 修改代码的工作量&#xff0c;主要是先部署项目&#xff0c;解…

微信小程序开发——比较两个数字大小

在这里我们使用的工具是 需要自行安装和配置。 在微信小程序中比较两个数字大小有以下几种方式&#xff1a; 一、普通条件判断 在小程序的.js 文件中&#xff0c;先定义两个数字&#xff0c;如let num1 5; let num2 3;。通过if - else if - else语句&#xff0c;根据num1与…

Machine Learning: A Probabilistic Perspective 机器学习:概率视角 PDF免费分享

下载链接在博客最底部&#xff01;&#xff01; 之前需要参考这本书&#xff0c;但是大多数博客都是收费才能下载本书。 在网上找了好久才找到免费的资源&#xff0c;浪费了不少时间&#xff0c;在此分享以节约大家的时间。 链接: https://pan.baidu.com/s/1erFsMcVR0A_xT4fx…

TypeScript:泛型

一、简介 软件工程中&#xff0c;我们不仅要创建一致的定义良好的API&#xff0c;同时也要考虑可重用性。 组件不仅能够支持当前的数据类型&#xff0c;同时也能支持未来的数据类型&#xff0c;这在创建大型系统时为你提供了十分灵活的功能。 在像C#和Java这样的语言中&#x…

银河麒麟桌面系统卸载应用报错快速解决

银河麒麟桌面系统卸载应用报错快速解决 1、问题简述2、解决方案步骤 1: 删除dpkg信息步骤 2: 强制卸载步骤 3: 验证与清理 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 1、问题简述 在银河麒麟桌面系统中卸载应用时&#xff0c;可能会遇…

16 训练自己语言模型

在很多场景下下&#xff0c;可能微调模型并不能带来一个较好的效果。因为特定领域场景下&#xff0c;通用话模型过于通用&#xff0c;出现多而不精。样样通样样松&#xff1b;本章主要介绍如何在特定的数据上对模型进行预训练&#xff1b; 训练自己的语言模型&#xff08;从头开…

DSLogic 逻辑分析仪的使用-I2C协议

一、I2C IIC-BUS&#xff08;Inter-IntegratedCircuit Bus&#xff09;最早是由PHilip半导体&#xff08;现在被NXP收购&#xff09;于1982年开发。 主要是用来方便微控制器与外围器件的数据传输。 它是一种半双工&#xff0c;由SDA&#xff08;数据&#xff09;和SCL&#xf…

USBCANFD卡再汽车电子行业中得应用

随着汽车电子的高速发展&#xff0c;车内信息的急剧增多&#xff0c;传统的CAN总线的数据传输能力已经很难满足车辆ECU的数据传输需求了&#xff0c;此时CANFD就应运而生了。 CANFD和CAN最主要的区别就是CANFD的ID段和数据段能够以不同的速率传输数据&#xff0c;这就保证了即使…

[数据集][目标检测]男女性别检测数据集VOC+YOLO格式9769张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;9769 标注数量(xml文件个数)&#xff1a;9769 标注数量(txt文件个数)&#xff1a;9769 标注…

使用 Milvus、vLLM 和 Llama 3.1 搭建 RAG 应用

vLLM 是一个简单易用的 LLM 推理服务库。加州大学伯克利分校于 2024 年 7 月将 vLLM 作为孵化项目正式捐赠给 LF AI & Data Foundation 基金会。欢迎 vLLM 加入 LF AI & Data 大家庭&#xff01;&#x1f389; 在主流的 AI 应用架构中&#xff0c;大语言模型&#xff0…

前端技术(七)——less 教程

一、less简介 1. less是什么&#xff1f; less是一种动态样式语言&#xff0c;属于css预处理器的范畴&#xff0c;它扩展了CSS语言&#xff0c;增加了变量、Mixin、函数等特性&#xff0c;使CSS 更易维护和扩展LESS 既可以在 客户端 上运行 &#xff0c;也可以借助Node.js在服…

【Redis】Redis 典型应用 - 缓存 (Cache) 原理与策略

目录 Redis 典型应⽤ - 缓存 (cache)什么是缓存使⽤ Redis 作为缓存缓存的更新策略1)定期⽣成2)实时生成 缓存预热&#xff0c;缓存穿透&#xff0c;缓存雪崩 和 缓存击穿关于缓存预热 (Cache preheating)什么是缓存预热 关于缓存穿透 (Cache penetration)什么是缓存穿透为何产…