带你了解什么是Java虚拟机运行时数据区

news2025/2/25 9:47:11

一、前言

程序都是运行在内存里的,所以对于一门开发语言来说,对于内存的管理都是重中之重的,前有C、C++需要开发者管理内存,后有Java的自动内存管理,到如今的内存安全的Rust。

二、运行时数据区概览

Java虚拟机在运行Java程序时会把其管理的内存划分为若干个区域。这些区域有些是随着Java虚拟机进程的启动而一直存在,有的区域是依赖用户线程的启动和结束而创建和销毁。在《Java虚拟机规范》中的规定,Java虚拟机所管理的区域如下:

​Java是支持多线程编程的,数据共享区域就是运行中的Java程序中的线程都可以访问的区域。反之,数据隔离区域线程私有的区域,每个线程都有的一块区域。

三、各运行数据区介绍

3.1 程序计数器

线程私有的一个区域,是一块较小的内存区域,可以看作是当前线程所执行的字节码的行号指示器。程序计数器指向下一条需要执行的字节码执行,是程序控制流的指示器,分支、循环、跳转、异常处理、线程回复等功能都需要依赖程序计数器来完成。

我们都知道多线程并发处理其实就是多个线程之间轮流切换,分配CPU的执行时间。在任何一个时刻一个处理器只会执行一个线程中的指令。因此在多个线程之间切换时,需要保留被切走的线程的执行现场,为了就是让这个线程重新得到CPU的执行时间时可以恢复到正确的执行位置,所以每个线程需要有一个独立的程序计数器,各个线程之间互不影响,独立存储。所以说程序计数器这块区域是“线程私有的”。

3.2 Java虚拟机栈

同样也是线程私有的内存区域,Java里面每个方法被执行的时候,Java虚拟机都会创建一个栈帧用于存储局部变量、操作数栈、动态链接、方法出口等信息。一个方法的调用到结束就是对应一个栈帧在Java虚拟机栈中入栈到出栈的过程。

局部变量表中存放了编译期间可知的各种基本数据类型、对象引用和returnAddress类型。局部变量表所需的内存空间在编译期间完成分配,在方法的运行期间不会改变局部变量表的大小。这里的"大小"指的是变量槽的数量,每个槽的大小是由虚拟机实现的,譬如按照一个槽32bit或64bit甚至更大。

《Java虚拟机规范》中规定了Java虚拟机栈的两类异常情况:

1、如果线程的请求的栈深度大于java虚拟机栈的深度将抛出StackOverflowError异常,如太深的递归容易导致此异常。

2、如果Java虚拟机栈容量可以动态扩展,当栈扩展时无法申请到足够的内存会抛出OutOfMemoryError

3.3 本地方法栈

与Java虚拟机栈的作用相似,其区别在于Java虚拟机栈为虚拟机执行Java方法服务的,而本地方法是为虚拟机使用到的本地方法服务的。在jdk源码中以native修饰就是本地方法,具体以对应的虚拟机来实现。例如:sun.misc.Unsafe里的很多方法就是本地方法。

《Java虚拟机规范》中没有规定本地方法栈使用的语言、使用方式与数据结构并没有任何的强制限制,因此具体的虚拟机可以自由的实现,例如Hot-Spot虚拟机直接把本地方法栈和虚拟机栈合二为一,所以也会像虚拟机栈一样会抛出stackOverflowError和OutOfMemotyError异常。

3.4 Java堆

虚拟机管理的内存中最大的一块,也是我们Java开发者最为关注的一块内存区域。Java堆是线程共享的一块内存区域,在虚拟机启动的时候创建,用于存放对象实例,Java中几乎所有的对象实例都在这里分配内存。由于即时编译技术的进步,尤其是逃逸分析技术的日渐强大,栈上分配、标量替换优化手段导致一些微妙的变化发生,所以说Java对象示例都在对上分配已经渐渐变得不是那么绝对。

以G1垃圾收集器为分界:

  • Hot-Spot虚拟机在G1垃圾收集器之前,垃圾收集都是分代收集,因此堆内存又被划分为老年代和新生代,默认老年代占堆空间的2/3,新生代占1/3。其中新生代又被划分为Eden和Survivor区,其中Survivor是由两个大小相等的区域组成:form和to。可以说G1之前的垃圾收集器都说是基于分代来设计的,需要新生代、老年代的收集器搭配才能工作。

  • G1出现之后,边不再区分新生代和老年代,Java堆使用同一个垃圾收集器

在《Java虚拟机规范》中规定,Java堆可以处于物理上不连续的内存空间上,但逻辑上应该是连续的。但是对于大对象,大多数虚拟机出于实现简单、存储高效的考虑,很有可能要求连续的内存空间。

Java堆的大小被实现成固定大小的,也可以是可扩展的,不过当前的主流的Java虚拟机都是可扩展来实现的,通过-Xmx和-Xms设置。如果Java堆中没有了内存可以分配给示例,并且堆无法扩展时,会抛出OutOfMemoryError的异常,也就是常说的OOM。

3.5 方法区

线程共享的一个内存区域,用于存储被虚拟机加载的类型信息、常量、静态变量、即时编译后的代码缓存等数据。

在JDK8之前,HotSpot虚拟机把垃圾收集器的分代设计扩展到了方法去,使用永久代来实现方法区。所以在JDK8之前会称方法区为永久代。这样做的原因是,这样做HotSpot的垃圾收集器可以像管理Java堆一样来管理这块内存区域。但是其他的Java虚拟机是没有永久代这一个概念的。

到了JDK6后,HotSpot虚拟机便放弃了使用永久代来实现方法区,而是使用本地内存来实现方法区,到了JDK7把原来放在永久代的字符串常量池、静态变量等移出(移到Java堆),而到了JDK8完全废弃了永久代的概念,改用像JRockit、J9一样在本地内存中实现的元空间来替代永久代。并且把JDK7中永久代剩下的内用全部移到元空间,这部分的内容主要是类型信息。

在《Java虚拟机规范》中的规定,对于方法区和Java堆一样不一定需要连续的内存和可以选择固定大小或者扩展外。甚至方法区还可以选择不实现垃圾收集。垃圾收集在方法区上是比较少出现的。方法区的回收目标主要是针对常量池的回收和对类型的卸载。同时也规定,如果方法区无法满足新的内存分配需求时,将抛出OutOfMemoryError异常。

3.6 运行时常量池

运行时常量池属于方法区的一部分。Class文件的类版本、字段、方法、接口等描述信息外,还有一项信息就是常量池表,用于存放编译期生成的各种字面量和符号引用,这部分内用将在类加载后存放在方法区的运行时常量池中。

一般来说出来保存Class文件中描述的符号引用外,还会把符号引用翻译出来的直接引用也存储在运行时常量池中。

运行时常量池相对于Class文件常量池的另外一个重要特性就是具备动态性,Java语言不要求常量只有编译器才能产生,并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可以将新的常量放入池中,这种特性被开发人员利用得最多的时String类的intern()方法。

运行时常量池是方法区的一部分,自然受到方法区内存的限制,当常量池无法再申请到内存时会抛出OutOfMemoryError异常。

3.7 直接内存

直接内存并不是Java虚拟机运行时数据区的一部分,也不在《Java虚拟机规范》中定义的区域。但是这一块区域也是被频繁使用,同时也有可能导致OutOfMemoryError异常。

在JDK1.4中加入了NIO,引入了基于通道(Channel)与缓冲区的I/O方式,它可以使用Native函数直接分配对外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块堆外内存的引用进行操作。以此来提升I/O性能,避免了在Java堆和Native堆中来回复制数据。

本机直接内存的分配不会收到Java堆大小的限制,但是使用的内存,所以会本机的总内存大小以及处理器寻址空间的限制,一般服务器管理员配置虚拟机参数时,会根据实际内存区设置Xmx等参数,但经常会忽略直接内存,使得各个内存区域总和大于物理内存本身,从而导致动态扩容的时候出现OOM。

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

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

相关文章

PyQt5可视化编程-菜单和工具栏

一、简介 PyQt5 是Digia的一套Qt5与python绑定的应用框架,同时支持2.x和3.x。本教程使用的是3.x。Qt库由Riverbank Computing开发, 是最强大的GUI库之一 ,官方网站:www.riverbankcomputing.co.uk/news。 PyQt5是由一系列Python模块…

Allegro上如何让飞线以方框形式显示

Allegro上如何让飞线以方框形式显示 Allegro可以让飞线以方框形式显示,让走线评估更简单,尤其是电源和地,如下图 选择Edit-Property Find选择Nets 选择需要改成方框显示的网络,左边选择Voltage,Value里面输入任意一个数字,比如0或者1,apply 可以看到网络已经显示成…

八.调试的技巧

目录 一.调试 1.何为调试? 2.调试的基本步骤 二.debug和release的介绍 三.Windows环境调试介绍 1.调试环境准备 2.学会快捷键 (1)F5 (2)F9 (3)F10 (4)F11 &am…

【Java学习】JavaWeb ---- JDBC

文章目录JDBC 快速入门ResultSet数据连接池JDBC 快速入门 下载jar包(百度)->add as library 代码 package com.ith.jdbc;import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement;public class demo1 {public stati…

HTTPS一定安全吗

https是一种通过计算机网络进行安全通信的传输协议,主要目的是提供对网站服务器的身份认证,保护交换数据的隐私与完整性,但不能说使用htttps就一定绝对的安全。 有一点需要了解的是,使用HTTPS 在内容传输的加密上使用的是对称加密…

使用dreamweaver制作采用DIV+CSS进行布局——美食甜品店铺加盟企业HTML静态网页 ——学生美食网页设计作品静态HTML网页模板源码

👨‍🎓静态网站的编写主要是用HTML DIVCSS JS等来完成页面的排版设计👩‍🎓,常用的网页设计软件有Dreamweaver、EditPlus、HBuilderX、VScode 、Webstorm、Animate等等,用的最多的还是DW,当然不同软件写出的…

C++标准库分析总结(九)——<适配器>

目录 1 适配器简介 2 适配器使用分类 2.1 容器适配器 2.2 函数适配器 2.2.1 常见的函数适配器 2.2.2 bind2nd 2.2.3 not1 2.2.4 bind用法 2.3 迭代器适配器 2.4 X适配器 1.6.1 ostream_iterator 1.6.2 istream_iterator 1 适配器简介 把一个原本存在的东西&#xf…

递归和排序算法的应用

一、递归常见问题和注意事项 1. 堆栈溢出; 2. 警惕重复运算: 可以使用一个数据结构(散列表)将已经计算过的f(k)保存起来,每当调用到f(k)时,先产看下是否已经求结果,从而避免重复计算。 3. 将递…

【嵌入式Linux】5.Ubuntu 交叉编译工具链安装

前言 交叉编译器中“交叉”的意思就是在一个架构上编译另外一个架构的代码,相当于两种架构“交叉”起来了。 其基本特点是: 1、它肯定是一个 GCC 编译器。 2、这个 GCC 编译器是运行在 X86 架构的 PC 上的。 3、这个 GCC 编译器是编译 ARM 架构代码的,也就是编译出来的可…

MongoDB 的安装、启动与连接

MongoDB 的安装、启动与连接一、MongoDB Community Server1. 安装(1) 下载(2) 安装1) 解压2) 配置环境变量3) 配置数据库存放目录a. 创建b. 赋权2. 启动验证二、MongoDB Compass安装三、连接一、MongoDB Community Server 1. 安装 (1) 下载 官网下载安装 (2) 安装 1) 解压…

three.js之访问几何体数据与几何体的旋转平移

文章目录访问几何体数据简介例子BoxGeometryPlaneBufferGeometry旋转、缩放、平移变换注意专栏目录请点击 访问几何体数据 简介 一般我们在开发项目的时候,可能会加载外部模型,这个时候,我们就需要获取到几何体的顶点数据这个时候&#xff…

Kubernetes入门

文章目录1、K8s快速入门1)简介2)架构(1)整体主从方式(2)master节点架构(3)Node节点架构3)概念4)快速体验(1)安装minikube(…

商城项目环境准备 — docker安装elasticsearch

文章目录一、操作系统虚拟内存设置为262144二、拉取elasticsearch镜像三、创建docker容器挂载的目录四、设置挂载文件访问权限五、启动elasticsearch六、访问一、操作系统虚拟内存设置为262144 原因:系统虚拟内存默认最大映射数为65530,无法满足ES系统要…

十万部冷知识:“梅西”是怎么炼成的

随着2022卡塔尔世界杯小组赛第二轮的打响,现在第一支确定被淘汰的队伍已经出现了,它就是东道主卡塔尔队。它也成了继南非世界杯以来,史上第二个小组赛出局的东道主。而在明天的凌晨3点C组的比赛中,广大球迷朋友们关注的阿根廷队也…

C/C++指针入门详解(一)

一、引言 指针是一个地址,这个地址不仅可以是变量的地址,也可以是其它数据结构的地址。为了方便调用这个地址,C/C是通过指针变量来使用这个地址的。而我们常说的指针,其实在一定程度上说的是指针变量,但是我们必须清楚…

通用后台管理系统前端界面Ⅺ——信息列表页(弹窗复用增改、CRUD前端基础实现)

因为需求发生了点变化&#xff0c;所以把之前的代码稍改一下&#xff0c;把之前的信息列表全复制到用户列表中&#xff0c;最后效果一样。UserList.vue <template><div class"UserList"><!-- 查询、重置 --><el-form :inline"true" :…

UnityShader_基础理论

渲染流程 此处的渲染流程只是一个概念流水线。大概分为应用阶段、几何阶段、光栅化阶段。 应用阶段 主要输出渲染所需的几何信息&#xff0c;包括点、线、三角面等&#xff0c;传递给下一阶段使用&#xff1b;这一阶段主要CPU处理&#xff0c;该阶段产生的产物就是渲染图元…

【ML特征工程】第 6 章 :降维:用 PCA 压缩数据薄饼

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

Java并发-synchronized使用方法

synchronized 关键字介绍 Java 中的每个对象都可以把它当作一个同步锁来使用&#xff0c;这些 Java 内置的使用者看不到的锁被称为内部锁&#xff0c;也叫作监视器锁。代码在进入 synchronized 代码块前会自动获取内部锁&#xff0c;这时候其他线程访问该同步代码块时会被阻塞…

十七、CANdelaStudio深入-创建新工程

本专栏将由浅入深的展开诊断实际开发与测试的数据库编辑,包含大量实际开发过程中的步骤、使用技巧与少量对Autosar标准的解读。希望能对大家有所帮助,与大家共同成长,早日成为一名车载诊断、通信全栈工程师。 本文介绍CANdelaStudio创建新工程的过程,欢迎各位朋友订阅、评论…