JVM之【运行时数据区1】

JVM简图

在这里插入图片描述

运行时数据区简图

运行时数据区

一、程序计数器(Program Counter Register)

1.程序计数器是什么?

程序计数器是JVM内存模型中的一部分,它可以看作是一个指针,指向当前线程所执行的字节码指令的地址。每个线程在执行过程中都有自己的程序计数器,因此程序计数器是线程私有的,独立于其他线程。

程序计数器不会OOM!!!

2.程序计数器的作用

  1. 指令执行:在每个线程执行字节码指令时,程序计数器会存储当前正在执行的字节码指令的地址。如果是正在执行本地方法(native method),那么程序计数器的值将是undefined。

  2. 指令跳转:在字节码指令执行完毕后,程序计数器会自动更新为下一条要执行的字节码指令的地址。通过这种方式,程序计数器可以确保字节码指令按顺序执行。

  3. 控制流管理:程序计数器帮助管理程序的控制流(如分支、循环、跳转等)。通过更新程序计数器的值,可以实现各种控制流指令(如if、for循环、switch等)的跳转逻辑。

  4. 多线程切换:由于Java是多线程的语言,每个线程都有自己独立的程序计数器。当线程切换时,程序计数器会保存当前线程的执行位置,当线程再次被调度时,程序计数器会恢复到之前保存的位置,以确保线程可以继续从正确的位置执行。


二、虚拟机栈(Java Virtual Machine Stack)

在Java虚拟机(JVM)中,每个线程在创建时都会创建一个虚拟机栈,虚拟机栈是每个线程私有的数据区,用于管理方法调用和执行。其内部保存一个个的栈帧(Stack Frame),对应着一次次的Java方法调用。每当一个线程调用一个方法时,JVM会为该方法创建一个新的栈帧(Stack Frame)并将其压入虚拟机栈中,方法执行完毕后,栈帧会从栈中弹出。

**存在OOM,但是不需要垃圾回收**

在这里插入图片描述

如何设置栈大小

-Xss:一般默认大小为1024KB
单位为bytes,还可以使用KB/MB/GB单位进行设置

栈帧(Stack Frame)

1、JVM直接对Java栈的操作只有两个,就是对栈帧的压栈和出栈,遵循“先进后出”/“后进先出”原则。在一条活动线程中,一个时间点上,只会有一个活动的栈帧。
2、只有当前正在执行的方法的栈帧(栈顶栈帧)是有效的,这个栈被称为当前栈帧(Current Frame),与当前栈帧相对应的方法就是当前方法(CurrentMethod),定义这个方法的类就是当前类(CurrentClass)。
3、执行引擎运行的所有字节码指令只针对当前栈帧进行操作。如果在该方法中调用了其他方法,对应的新的栈帧会被创建出来,放在栈的顶端,成为新的当前帧。
4、方法嵌套调用的极限次数,由栈的大小决定。超过大小时就会溢出OOM

在这里插入图片描述

1.栈帧的组成部分

  1. 局部变量表(Local Variable Array/Table)
  2. 操作数栈(Operand Stack)
  3. 动态链接(Dynamic Linking)
  4. 方法返回地址(Return Address)
  5. 附加信息(Additional Information)
    在这里插入图片描述

2.详细描述

1. 局部变量表(Local Variable Array/Table)
  • 原理
    • 局部变量表是一个数组,用于存储方法的局部变量,包括方法参数和方法内部定义的变量。 这些数据类型包括各类基本数据类型、对象引用,以及返回地址。
    • 局部变量表是建立在线程的栈上,是线程私有数据,不存在数据安全问题。
    • 局部变量表的容量大小,实在编译期间确定下来的,并保存在方法的Code属性的maximum local variables数据项中。在方法运行期间是不会改变局部变量表的大小的。
    • 方法嵌套调用的极限次数,由栈的大小决定。参数和局部变量越多,使得局部变量表膨胀,栈帧就越大,就会导致嵌套调用次数减少。
    • 表中的变量,只在当前方法调用中有效。方法调用结束后,随着栈帧的销毁,局部变量表随之销毁。
  • 作用:为每个方法提供存储和访问局部变量的空间。局部变量通过索引进行访问,索引从0开始。例如,int a = 10; 中的 a 就存储在局部变量表中。
  • 存储信息:存储了方法的参数和方法内部定义的局部变量。可以存储各种数据类型,包括基本数据类型(int、float、long、double等)以及对象引用。

大概看一下局部变量表
在这里插入图片描述
局部变量表

1、上图中,这里的参数名称、参数类型中的cp_info#,就是符号名称/符号引用,指的就是常量池中的内容。
2、以int 变量 a 为例,19、20 就对应了变量a和int类型
3、需要注意,非静态方法的局部变量表中,第一个序号0一定为this,指向当前方法。静态方法则没有
4、序号是slot,32位的类型占用1个slot,64位的占用两个slot,所以这里的序号都是1递增。如果使用double变量,就会看到序号会+2
5、不足32位的按照32来算,其中byte、short、char、boolean都会被转换为int来储存

在这里插入图片描述

2. 操作数栈(Operand Stack)
  • 原理
    • 操作数栈是一个LIFO栈,用于字节码指令执行时的临时存储空间。
    • 栈的最大深度在编译期就定义好了。并保存在方法的Code属性的max_stack数据中。
    • 和局部变量表类似,在栈中,32位的类型占用1个深度,64位的占用两个深度
  • 作用:在方法执行过程中,用于保存中间计算结果、传递参数以及存储返回值。例如,执行加法操作 i + j 时,会将 ij 压入操作数栈,执行完加法操作后,将结果存储在操作数栈中。
  • 存储信息:方法执行过程中临时存储的操作数、中间计算结果。

举例
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3. 动态链接(Dynamic Linking)
  • 原理:每个栈帧包含指向运行时常量池中,该栈帧所属方法的引用,目的是为了支持当前方法的代码能够实现动态链接。
  • 作用
    • Java源文件倍编辑成字节码文件时,所有变量和方法引用,都作为符号引用,保存在常量池中(在上面局部变量表中,有截图)
    • 当一个方法调用另外其他方法时,动态链接会将符号引用转换为实际的方法内存地址。
      在这里插入图片描述
(1)静态链接和动态链接
  • 静态链接:
    当一个字节码文件被装载进JVM内部时,如果被调用的目标方法在编译期可知且运行期保持不变时。这种情况下将调用方法的符号引用转换为直接引用的过程称之为静态链接。
  • 动态链接:
    如果被调用的方法在编译期无法被确定下来,也就是说,只能够在程序运行期将调用方法的符号引用转换为直接引用,由于这种引用转换过程具备动态性,因此也就被称之为动态链接。
(2)早期绑定和晚期绑定

对应的方法的绑定机制为:早期绑定(EarlyBinding)和晚期绑定(Late Binding)。绑定是一个字段、方法或者类在符号引用被替换为直接引用的过程,这仅仅发生一次。

  • 早期绑定:
    早期绑定就是指被调用的目标方法如果在编译期可知,且运行期保持不变时即可将这个方法与所属的类型进行绑定,这样一来,由于明确了被调用的目标方法究竟是哪一个,因此也就可以使用静态链接的方式将符号引用转换为直接引用。
  • 晚期绑定
    如果被调用的方法在编译期无法被确定下来,只能够在程序运行期根据实际的类型绑定相关的方法,这种绑定方式也就被称之为晚期绑定。

** 这里主要还是针对多态的 **

4. 方法返回地址(Return Address)
  • 原理
    • 在方法调用时,返回地址会记录调用方法的指令地址,以便方法返回时能找到正确的返回位置。
    • 方法返回有两类:正常完成、异常退出
    • 正常返回时,会调用方法的下一条指令
    • 异常退出时,需要通过异常表来确定,栈帧不保存相关信息
  • 作用:方法执行完毕后,返回到调用该方法的地方继续执行。这个地址一般是调用方法的下一条指令。
  • 本质上,方法的退出就是当前栈帧出栈的过程。此时,需要恢复上层方法的局部变量表、操作数栈、将返回值压入调用者栈帧的操作数栈、设置PC寄存器值等,让调用者方法继续执行下去。
  • 正常完成出口和异常完成出口的区别在于:通过常完成出口退出的不会给他的上层调用者产生任何的返回值。
5. 附加信息(Additional Information)
  • 原理:附加信息因JVM实现而异,包括栈帧的一些其他信息,比如调试信息和性能分析信息。
  • 作用:为JVM提供更多的运行时信息支持,如异常处理信息、JVM优化信息等。

课后问答

  1. 举例栈溢出的情况?(StackOverflowError)
  2. 调整栈大小,就能保证不出现溢出吗?
  3. 分配的栈内存越大越好吗?
  4. 垃圾回收是否会涉及到虚拟机栈?
  5. 方法中定义的局部变量是否线程安全?

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

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

相关文章

Python魔法之旅-魔法方法(04)

目录 一、概述 1、定义 2、作用 二、主要应用场景 1、构造和析构 2、操作符重载 3、字符串和表示 4、容器管理 5、可调用对象 6、上下文管理 7、属性访问和描述符 8、迭代器和生成器 9、数值类型 10、复制和序列化 11、自定义元类行为 12、自定义类行为 13、类…

Tensorflow入门实战 P02-彩色图片分类

目录 1、序言 2、主要代码 3、运行结果展示 (1)展示cifar10里面的20张图片 (2)预测的图片 (3)模型评估 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K…

postgressql——ReadBuffer_common函数(7)

PostgreSQL中ReadBuffer_common函数 数据结构 BufferDesc 共享缓冲区的共享描述符(状态)数据 typedef struct BufferDesc {//buffer tagBufferTag tag; /* ID of page contained in buffer *///buffer索引编号(0开始)int buf_id; /* buffers i…

大语言模型(一)OLMo

一、简介 OLMo 是由AI2 发布的大语言模型以及构建框架,与大多数之前的尝试只发布模型权重和推理代码不同,OLMo 开源了整个框架,包括训练数据、训练代码以及模型评估代码。 OLMo框架包括构建和研究语言模型所需的工具和资源。对于训练和建模,它包括完整的模型权重、训练代…

SZJG-离线环境成功安装Python和pip

在离线环境下安装Python和pip,可以按照以下步骤进行。假设你已经下载了Python的安装包 (Python-3.10.13.tgz)。 步骤 1:准备安装包 将 Python-3.10.13.tgz 拷贝到目标机器上的一个目录中,例如 /home/user/。 步骤 2:解压安装包…

4万字长文让人看懂ElementUI面试题及参考答案

ElementUI是什么?请简述其主要特点。 ElementUI是一个基于Vue.js的桌面端组件库,由饿了么团队开发并维护。它旨在为开发人员提供一套用于构建网页应用程序的高质量UI组件。ElementUI遵循Vue.js的设计思想,使得开发者可以快速地构建出风格统一、功能丰富的界面。 主要特点:…

水经微图PC版4.3.10发布

让GIS更简单高效,让地图更丰富及时! 水经微图(以下简称“微图”)新版已上线,在该版本中主要新增了天地图历史影像查看功能,以及其它功能的优化。 当前版本 当前版本号为:4.3.10 如果你发现该…

Pytorch反向传播算法(Back Propagation)

一:revise 我们在最开始提出一个线性模型。 x为我们的输入,w为权重。相乘的结果是我们对y的预测值。 那我们在训练时就是对这个权重w进行更新,就需要用到上一章提到的梯度下降算法,不断更新w。但是此时注意不是用y的预测值对w进…

linux centos nfs挂载两台服务器挂载统一磁盘目录权限问题

查看用户id id 用户名另一台为 修改uid和gid为相同id,添加附加组 usermod -u500 -Gwheel epms groupmod -g500 epms

网络协议。

一、流程案例 接下来揭秘我要说的大事情,“双十一”。这和我们要讲的网络协议有什么关系呢? 在经济学领域,有个伦纳德里德(Leonard E. Read)创作的《铅笔的故事》。这个故事通过一个铅笔的诞生过程,来讲述…

[代码复现]Self-Attentive Sequential Recommendation(ing)

参考代码:SASRec.pytorch 可参考资料:SASRec代码解析 前言:文中有疑问的地方用?表示了。可以通过ctrlF搜索’?。 环境 conda create -n SASRec python3.9 pip install torch torchvision因为我是mac运行的,所以device是mps 下面…

算法(七)插入排序

文章目录 插入排序简介代码实现 插入排序简介 插入排序(insertion sort)是从第一个元素开始,该元素就认为已经被排序过了。然后取出下一个元素,从该元素的前一个索引下标开始往前扫描,比该值大的元素往后移动。直到遇到比它小的元…

Caliburn.Micro框架学习笔记——Action的参数传递机制

据此篇文章,我们继续来谈谈Caliburn.Mirco的Action参数传递机制。因此程序结构都是默认MVVM的形式。 基本机制 它的机制是—— Caliburn.Micro 的智能对象参数绑定机制通过约定和反射使得视图和视图模型之间的交互变得更加直观和简洁。通过 cal:Message.Attach 语…

【C语言】探索文件读写函数的全貌

🌈个人主页:是店小二呀 🌈C语言笔记专栏:C语言笔记 🌈C笔记专栏: C笔记 🌈喜欢的诗句:无人扶我青云志 我自踏雪至山巅 🔥引言 本章将介绍文件读取函数的相关知识和展示使用场景&am…

vue中如何进行Markdown文档展示与解析

vue中如何进行Markdown文档展示与解析 一、安装插件二、如何使用 需求&#xff1a;接口返回了一个政策详情页面&#xff0c;里面有图片&#xff0c;用v-html展示的是url&#xff0c;所以改用vue-markdown 一、安装插件 npm install vue-markdown --save二、如何使用 <vue-…

RabbitMQ 如何保证消息不丢失

开启消息确认机制&#xff1a; 在发布消息时&#xff0c;可以设置deliveryMode为2&#xff08;持久化&#xff09;&#xff0c;以确保消息不会因为RabbitMQ的崩溃而丢失。 使队列持久化&#xff1a; 通过设置durable为true&#xff0c;可以确保队列在RabbitMQ重启后依然存在。…

Python 实战:打造智能进销存系统

想象一下&#xff0c;在繁忙的商店里&#xff0c;每天都有数以百计的商品进进出出&#xff0c;库存在不断变化&#xff0c;销售数据涌入&#xff0c;而你却能轻松应对一切。是的&#xff0c;Python 可以帮你实现这一切。本文将教你如何使用 Python 构建一个智能的进销存系统&am…

学习记录-5.30

学习记录-5.30 同步在我的博客可以来看看 http://www.zhihuigou.top/ ### Golang为什么比别的语言跟擅长并发: 首先是因为Goroutine&#xff0c;算是go的一个最大的特色 是轻量级的线程,创建一个goroutine的开销非常小,大约几KB,且调度开销很低 并且goroutine的调度,并不…

React组件通信——兄弟组件

兄弟组件通信 方法一&#xff1a;状态提升 子组件先将数据传递到父组件&#xff0c;父组件再把数据传到另一个子组件中。 import { useState } from "react"; // 定义A组件&#xff0c;向B组件发送数据 function A({ onGetMsg }) {const name "this is A na…

fyne apptab布局

fyne apptab布局 AppTabs 容器允许用户在不同的内容面板之间切换。标签要么只是文本&#xff0c;要么是文本和一个图标。建议不要混合一些有图标的标签和一些没有图标的标签。 package mainimport ("fyne.io/fyne/v2/app""fyne.io/fyne/v2/container"//&…