Java 虚拟机内存区域划分 - Higurashi

概要

在 Java 8 中,虚拟机内存主要由以下几个部分组成:

程序计数器(Program Counter Register):用于保存当前线程执行的位置,可以看作是当前线程所执行的字节码的行号指示器,当线程被切换后,用来恢复线程执行的位置。为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器。

虚拟机栈(Java Virtual Machine Stacks):用于存储局部变量表、操作数栈、动态链接、方法出口(方法返回地址)等信息。每个线程都拥有一个虚拟机栈,它的生命周期与线程相同。

本地方法栈(Native Method Stack):它与虚拟机栈相似,只是为本地方法服务。

堆(Heap):它是 Java 虚拟机中内存最大的一块,用于存储对象实例。堆为所有线程共享,是非线程安全的。是垃圾收集器管理的主要区域,因此也被称为“GC 堆”。

  • 字符串常量池(String Constant Pool):堆的一部分,专门存储字符串。

方法区(Method Area):它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。JDK7 及之前,HotSpot 虚拟机通过永久代(PermGen)实现方法区,在 JDK8 之后,永久代被元空间(Meta Space)所取代。

  • 运行时常量池(Runtime Constant Pool):方法区的一部分,用于存储编译期生成的各种字面量和符号引用。

直接内存(Direct Memory):直接内存 (Direct Memory) 并不是虚拟机运行时数据区的一部分,也不是《Java 虚拟机规范》中定义的内存区域。但是这部分内存也被频繁地使用,而且也可能导致 OutOfMemoryError 异常出现。在 JDK 1.4 中新加入了 NIO(New Input/Output) 类,引入了一种基于通道 (Channel) 与缓冲区 (Buffer) 的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆里面的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆中来回复制数据。

img

程序计数器(Program Counter Register)

Java 8 中的程序计数器是一块较小的内存区域,用于记录当前线程执行字节码的位置,也就是指向下一条将要执行的指令的地址。

  • 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
  • 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。

程序计数器是线程私有的,也就是每个线程都有一个独立的计数器,程序计数器的值在线程之间是互相独立的,不会出现线程安全问题。它的生命周期随着线程的创建而创建,随着线程的结束而死亡。

另:程序计数器是唯一一个不会出现 OutOfMemoryError 的内存区域

虚拟机栈(VM Stack)

每个线程在创建时,Java 虚拟机会为其分配一个独立的虚拟机栈(下文简称栈),线程内的方法调用是通过其虚拟机栈实现的。

栈由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法返回地址。

方法调用的数据需要通过栈进行传递。每一次方法调用都会有一个对应的栈帧被压入栈中,每一个方法调用结束后,都会有一个栈帧被弹出。和数据结构上的栈类似,两者都是先进后出的数据结构,只支持出栈和入栈两种操作。

img

与程序计数器一样,虚拟机栈也是线程私有的,它的生命周期和线程相同,随着线程的创建而创建,随着线程的死亡而死亡。

在方法调用时,Java 虚拟机会将调用方法所需的参数、返回地址等信息压入该线程对应的虚拟机栈中,然后执行方法体中的代码。当方法执行完毕,返回时,Java 虚拟机会将之前压入虚拟机栈的信息弹出,并返回到调用该方法的位置。

Java 方法有两种返回方式,一种是 return 语句正常返回,一种是抛出异常。不管哪种返回方式,都会导致栈帧被弹出。也就是说,栈帧随着方法调用而创建,随着方法结束而销毁。无论方法正常完成还是异常完成都算作方法结束。

栈空间虽然不是无限的,但一般正常调用的情况下是不会出现问题的。不过,如果函数调用陷入无限循环的话,就会导致栈中被压入太多栈帧而占用太多空间,导致栈空间过深。那么当线程请求栈的深度超过当前 Java 虚拟机所允许的最大深度的时候,就抛出 StackOverFlowError 错误。

除了 StackOverFlowError 错误之外,栈还可能会出现 OutOfMemoryError 错误,这是因为如果栈的内存大小可以动态扩展,如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出 OutOfMemoryError 异常。

  • StackOverFlowError:若栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前 Java 虚拟机栈的最大深度的时候,就抛出 StackOverFlowError 错误。
  • OutOfMemoryError:如果栈的内存大小可以动态扩展,如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出 OutOfMemoryError 异常。

HotSpot 虚拟机的栈容量是不可以动态扩展的,所以在 HotSpot 虚拟机上不会由于虚拟机栈无法扩展而导致 OutOfMemoryError 异常——只要线程申请栈空间成功了就不会有 OOM,但是如果申请时就失败,仍然会出现 OOM。

以下是一个简单的示例代码,用于演示虚拟机栈的使用:

public class StackDemo {public static void main(String[] args) {int result = calculate(10);System.out.println("Result: " + result);}public static int calculate(int num) {if (num == 1) {return 1;}return num * calculate(num - 1);}
}

在上述代码中,calculate 方法使用了递归调用来计算 num 的阶乘。每次调用该方法时,都会将当前 num 的值及其他信息封装成栈帧压入虚拟机栈中,并在计算完下一次调用的结果后弹出。整个过程先会多次压入栈帧,直到 num 的值为 1 时,开始逐个弹出栈帧并将计算结果返回。

本地方法栈(Native Method Stack)

它为虚拟机使用到的本地方法提供栈支持,和虚拟机栈类似,区别是虚拟机栈为 Java 方法服务,本地方法栈为 Native 方法服务。栈的大小可以通过设置 -Xss 来控制,默认大小为 1MB。

《Java 虚拟机规范》对本地方法栈中方法使用的语言、使用方式与数据结构并没有任何强制规定,在 HotSpot 虚拟机中,直接就把本地方法栈和虚拟机栈合二为一。

堆(Heap)

堆(Heap)是 Java 虚拟机用于存放对象实例的区域,是 JVM 中最大的一块内存区域,可以通过设置 -Xmx 和 -Xms 来控制最大和最小值。堆内存是线程共享的,因此在多线程的情况下需要进行并发控制。

在 Java 程序中,每当使用 new 关键字创建一个对象时,JVM 会自动在堆内存中为该对象分配内存空间,并返回该对象的引用。堆是垃圾收集器所管理的内存区域,当堆中没有可用内存时,会抛出 OutOfMemoryError 异常。

从垃圾回收的角度,由于现在收集器基本都采用分代垃圾收集算法,所以 Java 堆还可以细分为:新生代和老年代;再细致一点有:Eden、Survivor、Old 等空间。进一步划分的目的是更好地回收内存,或者更快地分配内存。

Java 世界中“几乎”所有的对象都在堆中分配,但是,随着 JIT 编译器的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。从 JDK 1.7 开始已经默认开启逃逸分析,如果某些方法中的对象引用没有被返回或者未被外面使用(也就是未逃逸出去),那么对象可以直接在栈上分配内存。

方法区(Method Area)

方法区属于是 JVM 运行时数据区域的一块逻辑区域,是各个线程共享的内存区域。用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。永久代空间不足会抛出 OutOfMemoryError 异常。

永久代(Permanent Generation)以及元空间(Metaspace)是 HotSpot 虚拟机对虚拟机规范中方法区的两种实现方式。并且,永久代是 JDK 1.8 之前的方法区实现,JDK 1.8 及以后方法区的实现变成了元空间。

元空间使用本地内存实现,不再像方法区那样有固定的大小限制,它的大小受限于操作系统的可用内存大小。

当虚拟机要使用一个类时,它需要读取并解析 Class 文件获取相关信息,再将信息存入到方法区。方法区会存储已被虚拟机加载的类信息、字段信息、方法信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

例如,下面的代码中定义了一个类 Person,其中包含一个静态变量 count 和一个静态方法 getCount:

public class Person {public static int count = 0;public static int getCount() {return count;}
}

在这个例子中,当这个类被加载时,类的信息(包括静态变量 count 和静态方法 getCount)就会被存储在方法区/元空间中。每个线程都可以通过调用 Person.getCount() 方法来获取 count 的值,因为它是共享的。

运行时常量池

Java 8 中的运行时常量池是指在类或接口中定义的常量的集合,包括编译期间确定的常量和运行期间确定的常量。它是一块位于方法区的内存区域,在类加载时被创建,用于存储类、接口、方法中使用的符号引用,如类名、字段名、方法名等,以及字面量常量(如字符串、数字)。

举个例子,假设有一个类如下所示:

public class Constants {public static final int COUNT = 100;public static final String NAME = "Java";
}

在类加载时,常量池会为该类创建一个常量池表,其中包含了 COUNT 和 NAME 这两个常量的值和引用。当其他类或方法引用 Constants.COUNT 或 Constants.NAME 时,实际上是从常量池中获取对应的值或引用。在运行时,如果需要创建字符串常量或使用字符串常量做参数,也会在常量池中创建相应的字符串对象。

字符串常量池

字符串常量池是 JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。当 Java 程序中创建字符串对象时,如果该字符串在字符串常量池中已经存在,则返回该字符串的引用;否则将该字符串添加到字符串常量池中,并返回新的引用。

JDK7 开始字符串常量池从方法区移动到堆中。

参考:Java 内存区域详解(重点)、JVM 之 方法区、永久代(PermGen space)、元空间(Metaspace)三者的区别

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

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

相关文章

使用modelsim仿真调用Xilinx IP核的通用方法

使用modelsim仿真调用Xilinx IP核的通用方法 使用modelsim仿真调用Xilinx IP核的通用方法 https://blog.csdn.net/weixin_39789553/article/details/108595621vivado 和 modesim 联合仿真&&快速修改重仿 https…

2025 年 11 月企业管理咨询公司权威推荐榜:战略规划与组织优化专业服务口碑之选

2025 年 11 月企业管理咨询公司权威推荐榜:战略规划与组织优化专业服务口碑之选 在当今复杂多变的商业环境中,企业面临着前所未有的战略挑战与组织变革压力。随着数字化转型加速、市场竞争加剧以及全球化进程深入,企…

2025 年 11 月企业管理咨询公司权威推荐榜:战略规划、组织优化与绩效提升领域的专业服务与口碑之选

2025 年 11 月企业管理咨询公司权威推荐榜:战略规划、组织优化与绩效提升领域的专业服务与口碑之选 在当今快速变化的商业环境中,企业面临着前所未有的挑战与机遇。战略规划、组织优化与绩效提升作为企业管理咨询的核…

自写new

function myNew(constructor, ...args) {// 参数验证if (typeof constructor !== function) {throw new TypeError(myNew: First argument must be a function);}// 1. 创建新对象,继承构造函数的原型const instance …

寺庙小程序开发公司,3家特色寺庙小程序开发公司业务详解:北京小程序/支付宝小程序/抖音小程序/活动小程序全涵盖公司推荐

开头:数字化浪潮下,寺庙小程序的开发价值凸显随着数字化技术与传统场景的深度融合,寺庙作为承载文化传承与精神寄托的重要场所,也亟需通过数字化工具优化服务体验、拓宽传播路径。小程序凭借轻量化、易操作、无需下…

【源码+数据集+训练教程】基于YOLOv8+Flask+Layui的智能垃圾分类检测架构

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025年结实板材源头厂家权威推荐榜单:口碑板材/耐用板材/EO级板材源头厂家精选

在建筑与装饰材料领域,结实板材的耐久性、环保性及适配性直接影响工程质量与使用寿命。行业数据显示,高品质板材可提升装饰工程寿命30%-50%,而环保型板材的市场需求年增长率达15%。本文基于产品物理性能、行业应用覆…

万能欧几里得算法 笔记

\[\newcommand{\floor}[1]{\left\lfloor #1 \right\rfloor} \newcommand{\ceil}[1]{\left\lceil #1 \right\rceil} \renewcommand{\sf}[2]{\begin{bmatrix} #1 \\ #2 \end{bmatrix}} \renewcommand{\ss}[2]{\begin{Bma…

2025年11月中国十大咨询公司权威推荐榜:战略管理、财务顾问与数字化转型顶尖品牌深度解析

2025年11月中国十大咨询公司权威推荐榜:战略管理、财务顾问与数字化转型顶尖品牌深度解析 在当今复杂多变的商业环境中,专业咨询服务已成为企业提升竞争力的关键要素。随着数字化转型浪潮的深入推进,企业对战略管理…

课程小程序开发公司,3家专业课程小程序开发公司能力拆解:抖音小程序/支付宝小程序/微信小程序全涵盖

随着在线教育场景的深度渗透,课程小程序凭借轻量化、即用即走的特性,逐渐成为教育机构连接用户的核心入口。从知识付费到职业培训,从K12辅导到兴趣课程,不同类型的教学需求对小程序的功能、体验与扩展性提出了差异…

四川如何选到专业的PET塑钢打包带生产厂家?求靠谱推荐

四川如何选到专业的PET塑钢打包带生产厂家?求靠谱推荐一、公司介绍:技术积淀与规模实力并存四川省新展星包装制品有限公司是一家专业从事PET塑钢打包带生产的四川打包带厂家,成立于2023年7月25日,前身为深耕行业多…

2025年冷拔精密管批发厂家权威推荐榜单:精密管/热轧无缝管/精密光亮管源头厂家精选

在机械制造、汽车液压系统与医疗器械领域,冷拔精密管作为关键结构件与流体输送载体,其尺寸精度、力学性能及表面质量直接影响设备可靠性。行业数据显示,高品质冷拔精密管的尺寸公差可控制在0.05mm以内,液压系统用管…

.NET Core嵌入式编程开关量GPIO(控制2个灯泡交替闪烁)

.NET Core嵌入式编程开关量GPIO(控制2个灯泡交替闪烁)一、在树莓派中安装.NET Core运行时 1、到微软的官方站点下载.NET Core运行时 下载地址2、选择Linux 中的ARM32, 如果不需要跑web,可以选择更精简的.NET Co…

切换到root的方式

sudo -s:通过当前用户密码验证,临时切换到root权限(不加载root环境变量,工作目录不变)。su root:需输入root用户密码,切换到root权限(加载root环境变量,工作目录变为root的家目录)。

2025 十大 LED 移动快拼折叠大屏标杆厂家 高效流动场景首选品牌推荐

LED 移动快拼折叠大屏凭借 “快速拼装、灵活移动、省空间” 的核心优势,已成为巡回演出、临时展会、政企会务等流动场景的核心显示设备。2025 年行业技术向 “智能化、高稳定性、全场景适配” 升级,本文结合技术专利…

使用Maven导入Junit5依赖时的注意事项

原先我的Maven中Junit5依赖如下:<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>RELEASE</version><scope>tes…

构造测试用例

1.SOC验证中,测试用例不要写的太复杂,逻辑单一可控性强很重要; 2.灵活使用define和$test$plusargs,隔离不同的验证场景; 3.基于以上两点,纯随机的CASE不如通过 define和$test$plusargs 来约束随机的 CASE ;这样…

WireShark抓包http,解密https - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025年耐磨陶瓷衬板订制厂家权威推荐榜单:陶瓷橡胶复合板/二合一陶瓷衬板/氧化铝陶瓷片源头厂家精选

在电力、矿山、水泥、钢铁等重工业领域,耐磨陶瓷衬板作为抵抗物料冲刷、延长设备寿命的关键部件,其硬度、韧性及定制适配性直接影响设备连续运行时间与维护成本。据行业数据统计,高品质耐磨陶瓷衬板可降低设备磨损率…

2025 年 11 月企业转型升级服务机构权威推荐榜:战略咨询、数字化改造与组织优化服务实力品牌深度解析

2025 年 11 月企业转型升级服务机构权威推荐榜:战略咨询、数字化改造与组织优化服务实力品牌深度解析 在全球经济格局深刻变革的背景下,企业转型升级已成为提升核心竞争力的关键路径。根据最新行业数据显示,超过78%…