JVM 主要组成部分与内存区域

news2025/1/5 8:16:25

一、JVM 主要组成部分:

JVM的主要包含两个组件和两个子系统,分别为:

(1)本地库接口(Native Interface):与native lib(本地方法库)交互,融合其他编程语言为Java所用,是与其它编程语言交互的接口

(2)运行时数据区(Runtime data area():即常说的JVM内存

(3)类加载子系统(Class loader):根据全限定类名装载class文件到运行时数据区的方法区中

(4)执行引擎子系统(Execution engine):也叫解释器,负责解释class指令,再提交给操作系统执行

 通过上面的图,我们可以大致知道Java代码是如何运行的:首先通过编译器将Java源代码转换成字节码,接着类加载系统把字节码加载到运行时数据区的方法区内,再使用执行引擎将字节码翻译成底层系统指令,最后交由 CPU 去执行,而这个过程中可能需要调用其他语言的本地库接口来实现整个程序的功能。

字节码只是 一套 JVM 指令集规范,并不能直接交给底层操作系统去执行,因此需要通过执行引擎将字节码翻译成底层系统指令

二、JVM 内存:

JVM 在执行 Java 程序时,会将内存划分为若干个不同的数据区域,不同的区域用途不同,创建和销毁时间也不相同。但在 JDK1.8 版本之后对运行时数据区域做了些修改,下面我们分别来看看修改前后的内存区域是怎么样的。

1、JDK1.8之前的JVM内存区域:

2、JDK8之后的JVM内存区域

3、各区域的的作用:

1.虚拟机栈(或叫线程栈)

官方叫法虚拟机栈,更好理解的叫法可以叫线程栈,为什么叫线程栈,因为每个线程只要开始运行,JAVA虚拟机就会给线程挖一块内存出来当做栈,用来存放线程的局部变量等,而栈中的操作是由一个个的栈帧组成,

以上面这个类为例,运行时首先main()方法作为第一个栈帧入栈,在栈帧中调用了computer()方法,那么就会将computer()这个方法进行入栈,后面执行到其他方法依次类推。而一个方法执行完后那么就出栈销毁。

而一个栈帧中还有局部变量表、操作数栈、动态链接、方法返回地址。

局部变量表:用于存储方法参数和方法内部定义的局部变量。

操作数栈:操作数栈主要用于执行方法时进行数据操作和计算。

动态链接:用于在运行时解析方法调用。

方法返回地址:,用于保存方法调用结束后的返回地址。当方法执行完成时,程序需要跳转回方法调用点继续执行。

当我们编译好一个java类后,会生成对应的.class文件,即字节码文件。

可以通过jvm -p命令对该文件进行反汇编

可以看到java代码int a=1这行代买对应的jvm指令,iconst_1: 将int类型常量1压入操作数栈istore_1:将int类型值存入局部变量

之后执行到int c=a+b这行代码

那么对应的指令码部分就是如图所示。

iload_1:从局部变量1中装载int类型值。iload_2:从局部变量2中装载int类型值。在此处即表示将变量a和变量b的值压入操作数栈。如下图所示

然后执行iadd指令,i代表int类型,add代表加法操作。那么就会从操作数栈中栈顶弹出两个对应的数,执行加法操作后,将数值写入操作数栈。

bipush 10就是将10压入操作数栈。imul和iadd同理

i++ 和 ++i 的区别:

  1. i++:从局部变量表取出 i 并压入操作栈(load memory),然后对局部变量表中的 i 自增 1(add&store memory),将操作栈栈顶值取出使用,如此线程从操作栈读到的是自增之前的值。
  2. ++i:先对局部变量表的 i 自增 1(load memory&add&store memory),然后取出并压入操作栈(load memory),再将操作栈栈顶值取出使用,线程从操作栈读到的是自增之后的值。

之前之所以说 i++ 不是原子操作,即使使用 volatile 修饰也不是线程安全,就是因为,可能 i 被从局部变量表(内存)取出,压入操作栈(寄存器),操作栈中自增,使用栈顶值更新局部变量表(寄存器更新写入内存),其中分为 3 步,volatile 保证可见性,保证每次从局部变量表读取的都是最新的值,但可能这 3 步可能被另一个线程的 3 步打断,产生数据互相覆盖问题,从而导致 i 的值比预期的小。

 

4.Java堆

用于存储对象实例,是占用内存最大的区域,可划分为新生代和老年代,新生代又可细分为 Eden区(伊甸园区)、From Survivor区(S0)、To Survivor区(S1)。

在 HotSpot 虚拟机中,对象在堆内存布局分成三部分:对象头,实例数据,对齐填充。

① 对象头:包括两部分的信息:

运行时数据:存储对象自身的运行数据,如哈希码,GC代年龄,锁状态、线程持有的锁、偏向线程ID等。

类型指针:即对象指向它的类型数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。如果对象是一个Java数组,那对象头中还必须有一块用于记录数组长度的数据。

② 实例数据:是对象真正存储的有效信息,是在程序代码中所定义的各种类型的字段内容,相同宽度的字段会被分配到一起。

③ 对齐填充:并不是必然存在的,仅起着占位符的作用。

 

 

当一个对象被new出来后,那么就放入了伊甸园区,当创建的对象越来越多,伊甸园区的内存不够时,那么就会触发垃圾回收GC(Garbage Collection),字节码执行引擎就会启动垃圾收集线程,执行Minor gc,当一个对象经过Minor gc后会被清除掉,或者是进入S0区和S1区,每经理一次GC对象头中的GC代年龄都会+1,超过15进入老年代,当老年代中内存不够时,就会触发Full GC,当年轻代和老年代中的内存都满了,且GC没有可回收的对象时,那么就会发生OOM(内存溢出)

5.元空间(方法区)

该区域被所有线程共享,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码(即class文件)等数据,同时,元空间中有一个运行时常量池用于存放静态编译产生的字面量和符号引用。该区域不需要连续的内存,并且可以动态扩展,动态扩展失败会抛出 OOM 异常,对该区域进行垃圾回收的主要目标是对常量池的回收和对类型的卸载,但是一般比较难实现。

如上图,常量testData,和User对象(也是存放的User对象的地址,指向堆中的User对象实例)

方法区是一个 JVM 规范,永久代与元空间都是其一种实现方式。JDK8 之前,Hotspot 中方法区的实现是永久代(Perm),JDK8 开始使用元空间(Metaspace),以前永久代的静态变量和常量池移至堆内存,其他内容移至元空间,元空间直接在本地内存分配。💡注:此处常量池指的是字符串常量池--常量池详解

那为什么要使用元空间取代永久代的实现?主要是为了方便管理方法区:

① 永久代与堆所使用的物理内存是连续的。对于永久代,由于类和方法等信息比较难确定大小,所以指定永久代的大小比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出,并且每次 Full GC 之后永久代的大小都会改变,如果动态生成很多 class 的话,就很可能出现 OOM,毕竟永久代的空间配置有限。

② JDK8之后,方法区存在于元空间,物理内存不再与堆内存连续,而是直接存在于本地内存中,理论上机器内存有多大,元空间就有多大。

③ 字符串存在永久代中,容易出现性能问题和内存溢出。

④ 永久代会为 GC 带来不必要的复杂度,回收效率偏低,因为方法区中类静态属性引用的对象、常量引用的对象都是 GC Roots 对象

直接内存

直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是 Java 虚拟机规范中定义的内存区域。

在 JDK 1.4 中新加入了 NIO,引入了一种基于通道(Channel)与缓冲区(Buffer)的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆中来回复制数据。

显然,本机直接内存的分配不会受到 Java 堆大小的限制,但是,既然是内存,肯定还是会受到本机总内存(包括 RAM 以及 SWAP 区或者分页文件)大小以及处理器寻址空间的限制。服务器管理员在配置虚拟机参数时,会根据实际内存设置 -Xmx 等参数信息,但经常忽略直接内存,使得各个内存区域总和大于物理内存限制(包括物理的和操作系统级的限制),从而导致动态扩展时出现 OutOfMemoryError 异常。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在鸿蒙本地模拟器中使用HDC工具

引言 HDC是指华为设备连接(Huawei Device Connector)工具。它的作用类似Android开发的ADB工具。在华为鸿蒙(HarmonyOS)操作系统的开发过程中,HDC工具起到了至关重要的作用。它允许开发者在开发主机(如 PC&…

ruoyi 分页 查询超出后还有数据; Mybatis-Plus 分页 超出后还有数据

修改:MybatisPlusConfig 类中 分页合理化修改为:paginationInnerInterceptor.setOverflow(false);

Unity中实现转盘抽奖效果(二)

如果要使转盘停止时转到到指定位置,应该如何做? 实现思路: 也就是在需要停止的分数的区间范围内,随机一个角度值,然后反推需要在哪个角度开始减速,如果转盘的当前角度和需要开始减速的角度有差值&#xf…

苍穹外卖04——Redis初入门 在店铺打烊or营业状态管理功能中的使用

Redis入门 redis简介 它以键值对的形式存储数据在内存中,并且以极高的性能和灵活性而著称,通常用于缓存、消息代理以及持久化数据。 - 基于内存存储,读写性能高- 适合存储热点数据(热点商品、资讯、新闻)- 企业应用广泛Windows版下载地址:https://github.com/microsoft…

深度学习每周学习总结R2(RNN-天气预测)

🍨 本文为🔗365天深度学习训练营 中的学习记录博客R5中的内容,为了便于自己整理总结起名为R2🍖 原作者:K同学啊 | 接辅导、项目定制 目录 0. 总结1. RNN介绍a. 什么是 RNN?RNN 的一般应用场景 b. 传统 RNN …

CUDA与Microsoft Visual Studio不兼容问题

简介:在安装一些 python库时,涉及到第三方库(特别是需要引用 C 代码)时,通常的安装方式会涉及到编译过程,通常称为"源代码安装"(source installation),或是 “…

WordPress网站中如何修复504错误

504网关超时错误是非常常见的一种网站错误。这种错误发生在上游服务器未能在规定时间内完成请求的情况下,对访问者而言,出现504错误无疑会对访问体验大打折扣,从而对网站的转化率和收入造成负面影响。 504错误通常源于服务器端或网站本身的问…

Springboot 升级带来的Swagger异常

当升级到Springboot 2.6.0 以上的版本后,Swagger 就不能正常工作了, 启动时报如下错误。当然如果你再使用sping boot Actuator 和 Springfox, 也会引起相关的NPE error. (github issue: https://github.com/springfox/springfox/issues/3462) NFO | jvm 1 | 2022/04…

发现API安全风险,F5随时随地保障应用和API安全

分析数据显示,目前超过90%的基于Web的网络攻击都以API端点为目标,试图利用更新且较少为人所知的漏洞,而这些漏洞通常是由安全团队未主动监控的API所暴露。现代企业需要一种动态防御策略,在风险升级成代价高昂、令人警惕且往往无法…

【数据结构】(Python)差分数组。差分数组与树状数组结合

差分数组: 基于原数组构造的辅助数组。用于区间修改、单点查询。区间修改的时间复杂度O(1)。单点查询的时间复杂度O(n)。差分数组的元素:第一个元素等于原数组第一个元素,从第二个元素开始是原数组对应下标的元素与前一个元素的差&#xff0…

12.30-1-5学习周报

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 文章链接摘要Abstract一、方法介绍1.HAT-CIR2.Horde3.DWGRNet 二、实验总结 文章链接 https://arxiv.org/pdf/2405.04101 摘要 本博客介绍了论文《Continual lea…

Android OpenGl(二) Shader

一、Shader 1、什么是Shader,为什么要使用Shder (1)shader运行在gpu上的小程序 (2)以前使用固定管线,但缺点是灵活度不够,无法满足复杂需求,为了解决固定管线的缺点,出…

【LeetCode】200、岛屿数量

【LeetCode】200、岛屿数量 文章目录 一、并查集1.1 并查集1.2 多语言解法 二、洪水填充 DFS2.1 洪水填充 DFS 一、并查集 1.1 并查集 // go var sets int var father [90000]intfunc numIslands(grid [][]byte) int {n, m : len(grid), len(grid[0])build(grid, n, m)for i …

[最佳方法] 如何将视频从 Android 发送到 iPhone

概括 将大视频从 Android 发送到 iPhone 或将批量视频从 iPhone 传输到 Android 并不是一件容易的事情。也许您已经尝试了很多关于如何将视频从 Android 发送到 iPhone 15/14 的方法,但都没有效果。但现在,通过本文中的这 6 种强大方法,您可…

MetaRename for Mac,适用于 Mac 的文件批量重命名工具

在处理大量文件时,为每个文件手动重命名既耗时又容易出错。对于摄影师、设计师、开发人员等需要频繁处理和整理文件的专业人士来说,找到一款能够简化这一过程的工具是至关重要的。MetaRename for Mac 就是这样一款旨在提高工作效率的应用程序&#xff0c…

QEMU网络配置简介

本文简单介绍下qemu虚拟机网络的几种配置方式。 通过QEMU的支持,常见的可以实现以下4种网络形式: 基于网桥(bridge)的虚拟网络。基于NAT(Network Addresss Translation)的虚拟网络。QEMU内置的用户模式网…

Elasticsearch向量检索需要的数据集以及768维向量生成

Elasticsearch8.17.0在mac上的安装 Kibana8.17.0在mac上的安装 Elasticsearch检索方案之一:使用fromsize实现分页 快速掌握Elasticsearch检索之二:滚动查询(scrool)获取全量数据(golang) Elasticsearch检索之三:官方推荐方案search_after…

MySQL:安装配置(完整教程)

这里写目录标题 一、MySQL 简介二、下载 MySQL三、安装 MySQL四、配置环境变量五、配置 MySQL5.1 初始化 MySQL5.2 启动 MySQL 服务 六、修改 MySQL 密码七、卸载 MySQL八、结语 一、MySQL 简介 MySQL 是一款广泛使用的开源关系型数据库管理系统(RDBMS)…

您的公司需要小型语言模型

当专用模型超越通用模型时 “越大越好”——这个原则在人工智能领域根深蒂固。每个月都有更大的模型诞生,参数越来越多。各家公司甚至为此建设价值100亿美元的AI数据中心。但这是唯一的方向吗? 在NeurIPS 2024大会上,OpenAI联合创始人伊利亚…

如何用CSS3创建圆角矩形并居中显示?

在网页设计中,圆角矩形因其美观和现代感而被广泛使用,居中显示元素也是一个常见的需求。今天,我们将学习如何使用CSS3的border-radius属性来创建圆角矩形,并将其居中显示在页面上。 如果你正在学习CSS,那么这个实例将非…