JVM(Java Virtual Machine)内存模型篇
前言
本文是JVM系列的内存模型篇,参考资料为《深入理解Java虚拟机》,本文章将会以HotSpot 虚拟机为介绍基础。
1.JVM简单介绍
Java Virtual Machine是运行Java程序的基础,JVM基于C、C++实现,JVM有很多种类,但是这些虚拟机都必须按照《Java虚拟机规范》来进行实现。目前JDK使用的是HotSpot虚拟机。
2.JVM内存模型
根据《Java虚拟机规范》的规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域
- 程序计数器
- Java虚拟机栈
- 本地方法栈
- 方法区
- 堆
分布如下图:

3.程序计数器
程序计数器是Java中占用内存比较少的一个区域,他的作用是记录当前线程所执行的字节码的行号指令,通俗的理解就是代码执行到哪里了。
我们很容易思考到,在多线程中,是发生线程切换这种情况的,那么一个线程被切换后,它的状态就需要被记录到上下文中,方便线程能正确执行到原来的位置,那么为了记录这个位置,就需要程序计数器来进行实现
为了线程切换后能恢复到正确的执行位置,每个线程都需要一个独立程序计数器,各个线程之间计数器互不影响,独立存储。因此它也是“线程私有”的内存
这片区域也是唯一一个在《Java虚拟机规范》中没有任何OutOfMemoryError情况的区域。
4.Java虚拟机栈
Java虚拟机栈,以“栈”命名的,在内存模型中,基本都是用来处理方法的,所以Java虚拟机栈是用来处理Java语言实现的方法的。同理的,这个栈也是线程私有的。他的生命周期与线程生命周期一样长。
一个线程在调用方法的时候,会在虚拟机栈中,创建一个栈帧,这个栈帧会存放局部变量表、操作数栈、动态连接、方法出口等信息。

栈帧包含以下内容:
-
局部变量表: 栈帧用于存储方法的局部变量,表中存放了编译期可知的基本数据类型和对象引用(对象引用指针或者句柄)。这些局部变量在方法调用时分配内存空间,并在方法调用结束后被释放。
-
操作数栈: 栈帧还包含一个操作数栈,用于存储方法执行时的操作数。当方法需要进行计算或操作时,操作数会被入栈或出栈。
-
动态链接: 栈帧包含指向运行时常量池中当前方法引用的指针,用于在方法中访问其他类或方法。
-
方法出口: 当方法调用完成后,程序需要返回到方法调用的地方继续执行。栈帧包含方法返回地址,用于记录返回的位置。
额外提一嘴的是当Java虚拟机栈的深度被方法调用填满的时候,就会出现StackOverFlowError;如果栈的大小动态扩展到没办法扩展的时候,会报OOM(OutOfMemoryError)的错误。
5.本地方法栈
这个栈和Java虚拟机栈是一样的功能,但是作用的对象不一样,Java虚拟机栈对应的是Java方法,而本地方法栈对应的是被Native标志的方法,这类方法一般都是C、C++代码。其他东西基本和Java虚拟机栈一致。
6.方法区
方法区与Java堆一样,是各个线程共享的内存区域,这块区域是用来存储已经被加载的类元信息,这些信息包含:类型信息、常量、静态变量、即使编译后的代码缓存等信息。
6.1永久代与元空间
早在JDK1.8以前,方法区使用的永久代的实现方式,而在1.8后才正式确定使用元空间。那么二者实现上有什么区别呢????
最大的区别就是前者是使用的虚拟机内存,后者使用了直接内存,也就是说永久代的内存大小受JVM限制,而元空间内存大小受真实机子内存大小限制,明显后者内存大小更大,前者更容易OOM。
在方法区使用元空间后,字符串常量池也从方法区移动到了堆内存中。
6.2运行时常量池
提到方法区,就不得不提到一个叫运行时常量池的东西,它也是方法区的一部分。
一个Class文件除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池表,用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
7.堆
堆内存是整个虚拟机中最大的一块,这块区域是被线程共享的,这块对象就是用来在程序执行时,大部分对象存放的地方(还有极小一部分可能会发生逃逸分析,在栈上创建和销毁)。
堆这块区域,也是最容易发生OOM的地方,原因可想而知,公共的地方,大家都来这里放东西,时间一长,没有空间也很正常,所以这块区域也是发生GC(Garbage Collected)频率最高的一个场所。(具体GC流程,下篇文章会详细介绍)
7.1 对象创建
堆中的对象(普通对象)创建过程也是比较讲究的,下面我们带着问题,一步一步理解这个过程
首先,如何创建?
很简单的,new关键字
那么问题又来了,对象创建依赖的信息从哪里来?
当Java遇到一条字节码new指令的时候,首先将去检测这个指令能否在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那么必须先执行相应的类加载(双亲委派模型)。
对象依赖信息得到后,内存大小该如何划分分配?
当一个类被加载之后,相应的对象创建所需的内存大小也就能被确定了。那么要在堆中创建对象,就需要划分空间,JVM中有两种划分空间的方式,分别是“指针碰撞”和“空闲列表”
- 指针碰撞
假设Java堆中内存分配绝对规整,使用过的和未使用的分成两边,只需要在边界设置指针,这个指针只需要挪动和对象大小一样的距离即可,这种就是指针碰撞- 空闲列表
假如Java堆内存并不规整,使用过的和未使用的都混在一起,这种情况,要分配内存就只能维护一个列表,这个列表记录了哪些内存可以使用,分配内存就需要在表中查找到足够到的区间进行分配即可,这就是空闲列表
并发下,对象创建的内存分配安全如何得到保证?
为我们所知的,堆内存是一个线程共享的,这就意味着,我们堆在划分内存大小的时候,可能会出现线程安全问题。可能出现线程1在给A分配大小的时候,还没来得及修改指针,但是线程2在创建B时,使用了这个指针,就导致了内存数据被改写了。解决这个问题有两个方式
- 加锁同步
实际实现中虚拟机是采用CAS+失败重试的方式保证更新操作的原子性- TLAB(Thread Local Allocation Buffer,本地缓冲区),也和ThreadLocal一样,给每个线程各自划分好区域,线程要创建对象,就在这个区域内创建就行,如果TLAB使用完了才需要进行同步锁定分配对象。如果JVM要使用TLAB,可以通过-XX:+/-UseTLAB参数来设定
实际上,内存分配成功之后,虚拟机还会对分配到的内存空间(不包括对象头)进行初始化工作,零值处理。这步操作是为了保证对象实例字段在Java代码中可以不赋值就能直接使用。
经历以上步骤,对象创建后,对象还需要设置什么?
需要设置“对象属于哪个类的实例”、“类的元数据信息“”、“对象hash码(实际调用Object::hashCode才会生成)”、“GC分代年龄”,这些信息都被描述在对象头中
最终
在上面工作都完成后,看似一个对象已经被创建了,但实际上,整个生命过程还差一步,即初始化,构造函数中的初始化工作还没有被真正执行,也就是 < init > ()方法,所以值都是默认为零值的,所以当构造函数执行完成后,一个对象就被完成创建了。
7.2 对象的内存布局
在了解一个对象的创建过程后,我们来看看,一个对象内部布局是如何的,直接看下图:

对象头:这部分包含了两部分信息
- 第一部分:HashCode、GC分代年龄、锁状态标记、线程持有的锁、偏向锁ID、偏向锁时间戳等信息等,这部分信息官方称之为:Mark Word,这部分数据在32位和64位虚拟机(未开启指针压缩)中分别占用32bit和64bit。
- 第二部分:类型指针,即对象指向它的类型元数据的指针,Java虚拟机通过这个指针来确定这个对象是哪个类的实例。如果是数组对象,对象头中还会记录数组长度,如果不是则无记录。
实例数据:这部分数据是对象真正存储的有效信息
对齐填充:这部分的内容不是必然存在的,也没有特殊含义,这部分的主要作用就是保证这个对象大小是8字节的整数倍,差多少,尽可能补多少。
JVM执行流程

-
代码编译:Java源代码通过Java编译器(javac)编译成字节码文件(.class文件)。
-
类加载:JVM的类加载器将字节码文件加载到内存中,并进行校验、准备、解析等处理。
-
内存分配:JVM为加载的类分配内存,包括方法区、堆、栈等。
-
初始化:JVM对类进行初始化,包括静态变量的赋值、静态代码块的执行等。
-
执行:JVM开始执行字节码指令,逐行读取字节码文件并执行。这个执行过程交给执行引擎将字节码翻译成CPU指令交给操作系统去执行
-
…
相关文章:
JVM(Java Virtual Machine)内存模型篇
前言 本文是JVM系列的内存模型篇,参考资料为《深入理解Java虚拟机》,本文章将会以HotSpot 虚拟机为介绍基础。 1.JVM简单介绍 Java Virtual Machine是运行Java程序的基础,JVM基于C、C实现,JVM有很多种类,但是这些虚…...
对地址解析协议ARP进一步探讨
之前在讨论MAC地址和IP地址时,顺便对ARP协议做了初步的总结 (计网第三章(数据链路层)(四)(MAC地址和IP地址、ARP协议、集线器和交换机)),但是当时对ARP请求的…...
java:java.util.StringTokenizer实现字符串切割
java:java.util.StringTokenizer实现字符串切割 1 前言 java.util工具包提供了字符串切割的工具类StringTokenizer,Spring等常见框架的字符串工具类(如Spring的StringUtils),常见此类使用。 例如Spring的StringUtil…...
IPV6 ND协议--源码解析【根源分析】
ND协议介绍 ND介绍请阅读上一篇文章:IPv6知识 - ND协议【一文通透】11.NDP协议分析与实践_router solicitation报文中不携带source link-layer address-CSDN博客 ND协议定义了5种ICMPv6报文类型,如下表所示: NS/NA报文主要用于地址解析RS/…...
Python学习笔记——存储容器
食用说明:本笔记适用于有一定编程基础的伙伴们。希望有助于各位! 列表 列表类似数组,其中可以包含不同类型的元素,写法如下: list1 [Google, Runoob, 1997, 2000] list2 [1, 2, 3, 4, 5 ] list3 ["a", …...
Android DI框架-Hilt
到底该如何理解<依赖注入> 模版代码:食之无味,弃之可惜 public class MainActivity extends Activity {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);TextView mTextView(TextView) findVi…...
基于寄生捕食优化的BP神经网络(分类应用) - 附代码
基于寄生捕食优化的BP神经网络(分类应用) - 附代码 文章目录 基于寄生捕食优化的BP神经网络(分类应用) - 附代码1.鸢尾花iris数据介绍2.数据集整理3.寄生捕食优化BP神经网络3.1 BP神经网络参数设置3.2 寄生捕食算法应用 4.测试结果…...
【Java常见的几种设计模式】
Java常见的几种设计模式 1. 单例模式(Singleton Pattern)2. 工厂模式(Factory pattern)3. 抽象工厂模式(Abstract Factory Pattern)4. 建造者模式(Builder Pattern)5. 原型模式&…...
jupyter崩溃进不去,报错module ‘mistune‘ has no attribute ‘BlockGrammar‘
是python包引起的问题 [E 2023-10-14 08:40:25.414 ServerApp] Uncaught exception GET /api/nbconvert?1697244025327 (127.0.0.1) HTTPServerRequest(protocol‘http’, host‘localhost:8090’, method‘GET’, uri‘/api/nbconvert?1697244025327’, version‘HTTP/1.1’…...
windows terminal鼠标右键打开
如果在官网上下载的是zip文件的 需要在注册表修改鼠标右键才能出来 注册表修改如下: 1.先windowsR,在命令框中输入regedit 打开注册表 2.在路径’计算机\HKEY_CLASSES_ROOT\directory\background\shell’下新建一个wt,wt下新建commond 这里…...
HTML5播放 M3U8的hls流地址
在HTML5页面上播放M3U8的hls流地址 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>视频播放</title> <script src"https://cdn.jsdelivr.net/npm/hls.jslatest"></script> &…...
leetcode:101.对称二叉树
借用二叉树是否相同的代码改动左右孩子相等对应关系,即为是否对称。 /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/bool isSameTree(struct TreeNode* p, struct Tr…...
UI自动化的适用场景,怎么做?
经常有人会问,什么样的项目才适合进行UI自动化测试呢?UI自动化测试相当于模拟手工测试,通过程序去操作页面上的控件。而在实际测试过程中,经常会遇到无法找到控件,或者因控件定义变更而带来的维护成本等问题。 哪些场…...
SpringFramewrok (1)
1、框架的概念与理解 在现实生活中,框架可以比喻为我们搭建房子的框架。 在框架的基础上,我们可以专注于我们自己的工作,而不用在意这些底层工作如何实现。 框架的优点包括以下几点: 1. 提高开发效率:框架提供了许多…...
电商独立站小程序开发方案
随着移动互联网的迅速发展,电商行业也逐渐向小程序平台转移。开发一款电商小程序对于拓展销售渠道、提高用户体验、增加用户忠诚度等方面都有着重要的意义。本文将围绕电商小程序的开发背景、需求分析、技术选型、开发流程、风险控制、商业模式和市场前景等方面进行…...
数据库安全运维是什么意思?数据库安全运维系统用哪家好?
我们大家都直到数据在某些情况下容易丢失或被破坏,攻击者可能通过对数据库进行破坏或勒索等手段获取利益。所以保障数据库安全至关重要。今天我们就来聊聊数据库安全运维是什么意思?数据库安全运维系统用哪家好? 数据库安全运维是什么意思&…...
小程序的console中出现:。。。不在以下 request 合法域名列表中,请参考文档:。。。的报错解决
报错效果: 其实这个报错不代表自己的代码有问题 但是本强迫症研究了一下,按照以下方法关掉就不会显示这个报错了。 点微信开发者工具中的右上角的详情。点本地设置。勾选不校验。。。HTTPS证书。 即可关闭该报错:...
计算机网络基础(三):IPv4编址方式、子网划分、IPv4通信的建立与验证及ICMP协议
**IPv4地址是一个32位长的二进制数。**而这个32位二进制数又通常会表示为4个用点隔开的十进制数。那么,这个32位二进制数要如何通过4个十进制数表示出来呢? 我们在配置IPv4地址时,同时配置的“掩码”又有何用途? 1.IPv4编址方式…...
Error: GlobalConfigUtils setMetaData Fail Cause:java.lang.NullPointerException
文章目录 1、在开发中会出现这样的错误。2、其次,再看其他错误: 1、在开发中会出现这样的错误。 完整错误:Caused by: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Error: GlobalConfigUtils setMetaData Fail ! Cause…...
OpenHarmony 应用全局的 UI 状态存储:AppStorage
AppStorage 是应用全局的 UI 状态存储,是和应用的进程绑定的,由 UI 框架在应用程序启动时创建,为应用程序 UI 状态属性提供中央存储。 和 AppStorage 不同的是,LocalStorage 是页面级的,通常应用于页面内的数据共享。而…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
