JVM-运行时数据区

news2024/11/19 18:33:03

目录

什么是运行时数据区?

方法区

程序计数器

虚拟机栈

局部变量表    

操作数栈       

动态连接

运行时常量池

方法返回地址

附加信息

本地方法栈

总结:


什么是运行时数据区?

     Java虚拟机在执行Java程序时,将它管理的内存分为不同的区域。这些区域用途不同,创建和销毁的时间也不同。有的随虚拟机进程启动一直存在,有的依赖用户线程启动和结束而创建和销毁。根据《Java虚拟机规范》,Java虚拟机管理的内存区域包括以下几个运行时数据区域。

来自《深入理解Java虚拟机(第3版)》

方法区

        方法区用于存储已被虚拟机加载的类型信息,常量,静态变量,即时编译器编译后的代码缓存等数据。可以理解为被线程共享的内存区域。
         根据《Java虚拟机规范》的规定,如果方法区无法满足新的内存分配需求时,将抛出
OutOfMemoryError异常。

        Java堆(Java heap)是虚拟机管理的最大一块内存,线程共享,虚拟机启动时创建,用于存储对象实例。虽然在《Java虚拟机规范》中对Java堆的描述是:“所有 的对象实例以及数组都应当在堆上分配”,但随着即时编译技术的发展,栈上分配,标量替换等优化手段,Java实例不仅仅分配在堆上。

        Java堆是垃圾回收的主要区域,HotSpot VM 的堆内存又分为新生代、老年代和永久代。新生代又分为Eden空间和Survivor空间。 常见的垃圾收集器也都是围绕这些内存区域进行工作的。将Java堆细分,主要是为了更好的回收内存或更快分配内存。

        根据《Java虚拟机规范》的规定,Java堆可以处于物理上不连续的内存空间中,但在逻辑上应是连续的,就像我们使用磁盘空间存储文件一样,并不要求所有文件连续存放。但对于大对象(典型的如数组对象),多数虚拟机实现出于实现简单、存储高效的考虑,很可能会要求连续的 内存空间。

        Java堆既可以被实现成固定大小的,也可以是可扩展的,不过当前主流的Java虚拟机都是按照可扩展来实现的(通过参数-Xmx和-Xms设定)。如果在Java堆中没有内存完成实例分配,并且堆也无法再扩展时,Java虚拟机将会抛出OutOfMemoryError异常。

程序计数器

      因为Java虚拟机中的多线程通过线程轮流切换、分配处理器的执行时间的方式实现,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。为了在线程切换后准确恢复到正确的执行位置,需要记录每个线程的所执行的字节码的行号,这时就需要程序计数器。

      程序计数器是一块较小的内存,每个线程都需要一个独立的程序计数器,每个线程之间程序计数器互不影响,独立存储,是“线程私有”的内存。在Java虚拟机的概念模型里,通过改变程序计数器的值选取下一条需要执行的字节码指令。程序计数器,是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础都需要依赖这个计数器完成。大家会想到程序在计算机上执行过程中的程序技术器,决定着程序执行的流程。

       如果执行的是本地(Native)方法,程序计数器的值则应为空(undefined),此区域是为一个一个在《Java虚拟机规范》中没有任何OutOfMemeoryError情况的区域

虚拟机栈

        Java虚拟机栈,也是线程私有的,和线程的生命周期相同。

        每个方法被执行时,Java虚拟机会同步创建一个栈帧,每个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中刚从入栈到出栈的过程。

栈帧由几部分组成?

      局部变量表,操作数栈,方法返回地址,动态连接,附加信息等。

局部变量表    

        我们知道方法由:访问修饰符(可选),返回值,方法名,参数列表,方法体组成。

        局部变量表,保存方法参数和方法内部的局部变量,在局部变量表中的存储空间以变量槽(slot)为单位,每个槽都应该能存放一个boolean,byte,char,short,int,float,reference或returnAddress类型的数据,这8种数据类型都可以使用32位或更小的物理内存累存储,且随着处理器、操作系统或虚拟机实现的不同而发生变化。局部变量表的空间在编译期即可根据源码和虚拟机的具体栈内存实现方式确定,不会受程序运行时数据的影响。

操作数栈       

        操作数栈,是一个先进后出的栈结构,用于临时保存方法执行过程的操作数。比如在进行加法运算:1+2=3时。

1. 将第一个操作数 1 压入操作数栈;

2. 将第二个操作数 2 压入操作数栈;

3. 从操作数栈弹出第二个操作数 2;

4. 从操作数栈弹出第一个操作数 1;

5. 将两个操作数相加得到结果 3;

6. 将结果 3 压入操作数栈;

7. 从操作数栈弹出结果 3;

       通过操作数栈,虚拟机可以方便地对运算中的操作数进行入栈和出栈,实现复杂的算术运算逻辑。它避免了每次运算都需要在堆内存中分配新的操作数对象,可以提高执行效率。高效地对方法运算过程中的操作数进行入栈出栈操作,这是实现Java虚拟机高效运行的重要组成部分。每个栈帧的操作数栈的深度,在编译器也可确定,在运行期间不会变。

动态连接

        在讲动态连接之前,我们先回顾一下运行时常量池的知识。

运行时常量池

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

        Class文件的常量池中存在大量的符号引用,字节码中的方法调用指令就以常量池里指向方法的符号引用作为参数。这些符号引用一部分会在类加载阶段或者第一次使用的时候被转为直接引用,这种转化被称为静态解析。另一部分将在每次运行期间都转化为直接引用,这部分称为动态连接。

        动态连接是指在程序运行时才去解析字节码中的符号引用,并把符号引用替换为直接引用的过程,主要为了支持Java动态绑定机制。动态绑定允许程序运行时才去决定实际调用的方法,给Java带来很大的灵活性,支持Java的多态特性。

举个例子:

public class Main {
  public static void main(String[] args) {
    Animal a = new Dog(); 
    a.run();
  }
}

class Animal {
  public void run() {
    System.out.println("Animal is running");
  }
}

class Dog extends Animal {
  @Override
  public void run() {
    System.out.println("Dog is running"); 
  }
}

        编译时,编译器只知道a是一个Animal对象,它不知道a最终会指向一个Dog对象。

        运行时,JVM通过动态连接,才会根据实际的对象类型Dog,动态地绑定到Dog.run()这个方法上,从而输出"Dog is running"。如果没有动态连接,那么只能静态地绑定到Animal.run(),就无法利用多态的特性了。所以动态连接是支持运行时多态以及动态绑定的关键。它让Java语言可以更灵活地处理对象的多态特性。       

方法返回地址

        方法执行完退出时,无论是遇到方法返回的字节码指令还是遇到异常退出,都需要返回到最初方法被调用的位置,程序才能继续执行。这个位置就是方法返回地址。

例如:

public int sum(int a, int b) {
  return a + b;
}

public static void main(String[] args) {
  int s = sum(1, 2);
  System.out.println(s);
}

        在main方法调用sum方法时,会先记录下 “int s = sum(1,2);” 这行代码的位置,当sum方法执行完返回结果后,返回到该位置,执行后面的“System.out.pringln(s);”方法。所以,方法返回地址,就是调用该方法的具体代码位置。

        JVM通过动态连接找到方法的入口,并记录下返回地址,以便在方法执行后正确返回到调用方。返回地址是实现正确的方法调用流程所必需的。动态连接使得返回地址可以在运行时确定,这样Java程序才可以实现动态绑定和灵活的函数调用机制。 

        而方法返回后,该方法对应的栈帧会出栈,栈顶的栈帧就是该方法的调用者,调用者的局部变量表可能会发生变化,这取决于方法的返回值是否被赋值给了调用者栈帧的某个局部变量。还以上面的方法为例,当sum方法执行完返回后,main方法栈帧的局部变量s被赋值为sum方法的返回值3。

附加信息

        附加信息,是指在进行方法调用时,除了明确的参数和返回值之外,还可以传递的一些额外信息。从理论上讲,它提供了一种传递方法调用的额外上下文的方式,对JVM内部来说可以提供更多信息。一些专业的程序分析和追踪工具可能会用到它们,对日常开发影响不大。

本地方法栈

        本地方法栈(Native Method Stack):与虚拟机栈类似,用于支持Native方法的执行。关于本地方法,可参考Java本地方法/Java native方法/JNI_jni native方法_小王师傅66的博客-CSDN博客

总结:

        JVM运行时数据区主要包括:方法区,堆,虚拟机栈,程序计数器,本地方法栈。

        方法区(Method Area):用于存储类信息、静态变量、静态方法等数据,可以理解为所有线程共享的内存区域。方法区无法满足新的内存分配需求时,会抛出OutOfMemeoryError异常;
        堆内存(Heap):用于存储对象实例,可以理解为所有线程共享的内存区域。如果在Java堆中没有内存完成实例分配,并且堆也无法再扩展时,Java虚拟机将会抛出OutOfMemoryError异常。可以通过调整-Xms和-Xmx参数调整堆空间;
        虚拟机栈(VM stack):用于存储局部变量表、操作栈、动态链接、方法返回地址/方法出口等信息,属于线程私有。每个线程都有自己的虚拟机栈。当线程请求的栈深度超过虚拟机所允许的最大深度时,就会抛出 StackOverflowError 异常。当虚拟机栈的空间无法分配时,将抛出 OutOfMemoryError 异常。可以通过调整-Xss参数调整栈空间;
        程序计数器(PC Register):用于存储指向下一条将要执行的指令的地址,每个线程都有自己的程序计数器,它的空间是非常小的,基本不会发生溢出的情况。
        本地方法栈(Native Method Stack):与虚拟机栈类似,用于支持Native方法的执行。本地方法栈也是线程私有,与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

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

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

相关文章

BI报表工具有哪些作用?奥威BI全面剖析数据

BI报表工具有哪些作用?主要的作用是通过整合多业务来源数据,全面分析挖掘数据,来帮助企业实现数据化运营、支持智能决策、实现数据资产沉淀和增值、进行数据挖掘和预测分析、提高数据可读性和数据可视化程度等,从而提高企业的竞争…

目标用户特征分析常见4大方法

用户特征分析直接影响需求分析、用户体验设计等软件开发的关键环节,如果不对用户特征进行科学分析,不能获得用户真实意图,这直接影响需求分析质量,对整个项目影响较大。 因此我们需要用科学的方法对目标用户进行特征分析。而常见的…

腾讯云-宝塔添加MySQL数据库

1. 数据库菜单 2. 添加数据库 3. 数据库添加成功 4. 上传数据库文件 5. 导入数据库文件 6. 开启数据库权限 7. 添加安全组 (宝塔/腾讯云) 8. Navicat 连接成功

深入了解PostgreSQL:高级查询和性能优化技巧

在当今数据驱动的世界中,数据库的性能和查询优化变得尤为重要。 POSTGRESQL作为一种开源的关系型数据库管理系统,在处理大规模数据和复杂查询时表现出色。 但随着数据量和查询复杂性的增加,性能问题可能会显现出来。 本文将深入探讨POSTGR…

机器学习深入浅出

机器学习是一种人工智能的分支,它使用算法和数学模型来让计算机自主学习数据并做出预测和决策。这种技术正在被广泛应用于各种领域,包括自然语言处理、计算机视觉、语音识别、医学诊断和金融预测等。在本篇博客中,我们将介绍机器学习的基本概…

python的decimal或者叫Decimal,BigDecimal

前言 在python中进行小数计算时,很容易发生精度错误问题!!!!一定要注意!!!或者说,只要进行小数的运算都要用decimal。如:银企对账;工程计算等等在…

(十一)大数据实战——hadoop高可用之HDFS手动模式高可用

前言 本节内容我们介绍一下hadoop在手动模式下如何实现HDFS的高可用,HDFS的高可用功能是通过配置多个 NameNodes(Active/Standby)实现在集群中对 NameNode 的热备来解决上述问题。如果出现故障,如机器崩溃或机器需要升级维护,这时可通过此种…

Amazon Aurora Serverless v2 正式发布:针对要求苛刻的工作负载的即时扩展

我们非常兴奋地宣布,Amazon Aurora Serverless v2 现已面向 Aurora PostgreSQL 和 MySQL 正式发布。Aurora Serverless 是一种面向 Amazon Aurora 的按需自动扩展配置,可让您的数据库根据应用程序的需求扩展或缩减容量。 亚马逊云科技开发者社区为开发者…

4 Promethues监控主机和容器

目录 目录 1. 监控节点 1.1 安装Node exporter 解压包 拷贝至目标目录 查看版本 1.2 配置Node exporter 1.3 配置textfile收集器 1.4 启动systemd收集器 1.5 基于Docker节点启动node_exporter 1.6 抓取Node Exporter 1.7 过滤收集器 2. 监控Docker容器 2.1 运行cAdviso…

ansible控制主机和受控主机之间免密及提权案例

目录 案例描述 环境准备 案例一--免密远程控制主机 效果展示: 解决方案 1.添加主机 2.通过ssh-key生成密钥对 3.生成ssh-copy-id 4.验证 案例二-----免密普通用户提权 效果展示 解决方案 1.使用普通用户,与案例一 一样,进行发送密钥…

不懂路由协议分类?这五个常用路由协议一定要掌握

摘要: 路由协议在计算机网络中起着非常重要的作用,用于选择数据包传输路径,能够帮助网络管理员有效地管理网络流量。路由协议有很多种,例如RIP、EIGRP、IS-IS等,那么路由协议如何分类?分享给大家一些常用的…

kubernetes之Ingress

一、背景 Ingress是k8s中实现7层负载的实现方式,是公开集群外部流量到集群内服务的HTTP和HTTPS路由 二、Ingress基础 通常Ingress实现由Ingress 控制器和Ingress组成,Ingress控制器负责具体实现反向代理及负载均衡,Ingress负责定义匹配规则和…

Pytorch(四)

目录 一、RNN(递归神经网络) 二、GAN(对抗生成网络) 三、OCR 四、注意力机制 一、RNN(递归神经网络) 主要应用于NLP(自然语言处理) 二、GAN(对抗生成网络) 原理:存在一个生成器与判别器,随着双方矛盾升级,从而双方性能不断增强。 GAN网络组成:生成网…

uniapp使用阿里图标

效果图: 前言 随着uniApp的深入人心,我司也陆续做了几个使用uniapp做的移动端跨平台软件,在学习使用的过程中深切的感受到了其功能强大和便捷,今日就如何在uniapp项目中使用阿里字体图标的问题为大家献上我的一点心得&#xff0…

【Linux】—— 进程的创建和退出

序言: 在上期,我们已经对 Linux的进程的相关知识进行了相关的学习。接下来,我们要学习的便是关于进程控制 的基本知识!!! 目录 (一)进程创建 1、fork函数初识 2、写时拷贝 3、f…

Vue2 第十三节 使用Vue脚手架 (二)

1. ref属性 2. props配置项 3.mixin混入 4.plugin插件 一. ref属性 ① 作用:用于给节点打标识(给元素或者组件注册引用信息,id的替代者) ② 语法: 应用在html标签上获取的是真实的DOM元素,应用在组件…

SpringCloudAlibaba之Nacos配置中心

第一步&#xff1a;引入jar包 <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> 第二步&#xff1a;在resources下创建一个bootstrap.yml文档…

微信可以防止被拉黑,原来这样设置→

微信真是隔三差五上个热搜&#xff0c;这不得被别的 App 羡慕死 这不&#xff0c;前几天#原来微信可以防拉黑#的话题冲上了热搜。 说到拉黑&#xff0c;大伙大部分应该都体验过&#xff0c;在生活中我们和好朋友之间难免有摩擦&#xff0c;往往有些朋友情绪一上来就把你拉黑了。…

20230802-下载jdk1.8、jre

搜索oracle oracle官网 https://www.oracle.com/cn/

举办活动发布会,如何得到媒体支持?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 举办活动发布会并得到媒体报道的支持是一个关键的宣传和推广手段。以下是一些建议&#xff0c;帮助你增加吸引媒体关注和报道的机会&#xff1a; 1. 策划新闻价值&#xff1a;确保你的发…