JVM理论(三)运行时数据区--PC寄存器/虚拟机栈/本地方法栈

news2024/9/23 5:22:55

运行时数据区(JVM内存结构)

JVM内存结构

内存是非常重要的资源,是硬盘和CPU的中间桥梁,承载操作系统和应用程序的实时运行.JVM内存布局规定java在运行过程中内存申请、分配、管理的策略,保证JVM高效稳定运行。不同的JVM对于内存划分和管理机制存在部分差异(如J9和JRocket没有方法区,而Hotspot存在) 。

运行时数据区包括堆、方法区、PC寄存器(即程序计数器)、虚拟机栈、本地方法栈。

其中黄色的为多个线程共享,绿色的为单独线程私有的,即:

  • 线程私有:PC寄存器(即程序计数器)、虚拟机栈、本地方法栈
  • 线程共享:堆、方法区(永久区)

 

PC寄存器(程序计数器

程序计数器作用示意图

概述

JVM中程序计数寄存器用来存储下一条将要执行指令的地址(当前线程所执行的字节码的行号指示器),执行引擎从PC寄存器获取到指令地址后进行执行对应的指令。

PC寄存器特点:

  • 内存空间很小几乎忽略不计
  • 运行速度最快的内存区域
  • 线程私有,与线程生命周期一致
  • 存储当前线程正在执行的java方法的指令地址
  • 不会出现OOM,无GC

常见问题

为什么要用PC寄存器记录当前线程的执行地址?使用它存储字节码指令地址有什么用?

因为CPU需要不停的切换各个线程,此时切换回来后,就得知道接着从哪里开始继续执行。

JVM的字节码解释器需要通过PC寄存器的值来明确下一条应该执行什么样的字节码指令。

PC寄存器为什么被设定为线程私有的?

程序通常运行在多线程环境下,CPU会不停的做任务切换,会导致程序经常中断和恢复,为了保证程序运行结果分毫不差,所以每个线程都有独立的PC寄存器,分别独立的记录各个线程正在执行的当前字节码指令地址,这样各个线程之间便可以独立计算,从而不会出现相互干扰,保证程序运行结果正确。

虚拟机栈 

虚拟机栈内部组成

概述

由于跨平台设计,Java的指令都是根据栈来设计的,不同平台的CPU架构不同,所以不能设计为基于寄存器的。

栈是程序运行时基本单位(即解决程序如何运行、处理数据),堆是存储单位(即数据如何存储,存储在哪里)。

虚拟机栈特点:

  • 跨平台
  • 指令集小,编译器容易实现
  • 性能相比寄存器下降(因为实现相同功能需要更多的指令)
  • LIFO/FILO(后进先出/先进后出)
  • 生命周期和线程周期保持一致
  • JVM对栈操作只有两个:方法执行(入栈/压栈)和方法结束(出栈)
  • 会出现OOM,无GC(因为只有进出栈)
  • 可以通过-Xss设置栈内存大小

栈运行原理

  • 不同线程中的栈帧是不允许存在相互引用的,即不可能在一个栈帧中引用另外一个线程的栈帧;
  • 如果当前方法调用了其他方法,在方法返回时候,当前栈帧会将此方法的结果给到前一个栈帧,随后JVM会丢弃当前栈帧,使得前一个栈帧重新成为当前栈帧;
  • 在java运行过程中正常的函数返回(return)和抛出异常都会导致栈帧被弹出.

栈帧

一个虚拟机栈内部保存多个栈帧,栈帧是虚拟机栈的基本组成单位,且每个栈帧对应java程序中的一个方法。栈帧是一个内存区块,即:

  • 局部变量表(局部变量数组/本地变量表)
  • 操作数栈(表达式栈)
  • 动态链接(指向运行时常量池的方法引用)
  • 方法返回地址(方法正常退出或者异常退出的定义)
  • 其他附加信息

注意:有的资料中也将动态链接、方法返回地址、其他附加信息统一称为栈数据区

局部变量表

  • 被定义为一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量。这些数据类型包括基本数据类型,对象引用以及方法返回地址类型
  • 局部变量表所需的容量大小是在编译期确定下来的,并保存在方法的code属性的maximum local varaiables数据项中,在方法运行期间是不会改变局部变量表大小
  • 属于线程私有数据,不存在数据安全问题
  • 局部变量表中的变量只在当前方法调用中有效,方法调用结束后,随着方法栈帧销毁,局部变量表也随之销毁
  • 局部变量表的存储基本单元被称为Slot(变量槽),32位的数据类型只占用一个slot,64位的类型占用两个slot
  • 若当前帧由构造方法或者实例方法创建,那么该对象引用this将会存放在index为0的slot中
  • 局部变量表中的slot是可以重用的,从而节省资源
  • 局部变量必须显示赋值,否则编译不通过,而成员变量存在默认赋值,可不用显示赋值
  • 局部变量表中的变量也是重要的垃圾回收根节点,主要被局部变量表直接或间接引用的对象都不会被回收

操作数栈(表达式栈)

操作数栈的作用就是在方法执行过程中,根据字节码指令,在栈中写入数据或者提取数据,即入栈(push)或者出栈(pop),比如执行求和,复制,交换等操作时。它的特点包括:

  • 保存计算过程的中间结果,同时作为计算过程中变量的临时存储空间
  • 操作数栈也会拥有一个栈深度用于存储数值。该深度也在编译期就定义好了,保存在方法的Code属性的max stack的值
  • 操作数栈并非采用访问索引的方式来进行数据访问,而只能通过标准的入栈和出栈操作来完成一次数据访问
  • 被调用方法有返回值时,该值也会被压入当前栈帧的操作数栈中

动态链接(指向运行时常量池的方法引用)

每个栈帧内部都包括一个指向运行时常量池中该栈帧所属方法的引用,该引用目的就是为了支持当前方法代码能够实现动态链接。

在Java源文件被编译到字节码文件中时,所有的变量和方法引用都作为符号引用保存在class文件的常量池里,而动态链接的作用就是为了将这些符号引用转换为调用方法的直接引用

扩展

方法绑定机制:早期绑定和晚期绑定

静态链接:当一个字节码文件被装载进JVM时,如果被调用的目标方法在编译期可知,且运行期保持不变,这种情况下降调用方法的符号引用转换为直接引用的过程称之为静态链接

动态链接:如果被调用的目标方法在编译期无法被确定,只能通过运行期间将符号引用转换为直接引用,称为动态链接

绑定是一个字段、方法或者类在符号引用被替换为直接引用的过程,仅发生一次。而早期绑定可以对应静态链接,晚期绑定对应动态链接。

方法返回地址

方法返回地址就是用来存放调用该方法的pc寄存器的值。方法结束有正常退出和异常退出:

  • 正常退出:调用者的pc寄存器的值作为返回地址,即调用该方法的指令的下一条指令地址
  • 异常退出:返回地址通过异常表来确定,栈帧中一般不会保存这部分信息,且不会给他的上层调用者产生任何返回值

本地方法栈

本地方法: 一个Native方法就是一个Java调用非Java代码的接口,它的初衷就是融合C/C++程序;使用本地方法,我们可以用Java实现了Jre与底层系统的交互。

Java虚拟机用于管理Java方法的调用,而本地方法栈用于管理本地方法的调用。本地方法栈也是私有的。和Java虚拟机特点基本相同。

常见问题

开发中JVM的栈遇到的异常

首先Java的虚拟机规范允许Java的栈大小是动态的或者固定不变的。

a.当采用固定大小时,若线程请求分配的栈容量超过虚拟机栈允许的最大容器容量,则JVM会抛出StackOverFlowError异常

b.当采取动态扩展时,当尝试扩展时候无法申请到足够内存或者没有足够内存创建对应的虚拟机栈,则会抛出OutOfMemoryError异常

调整栈大小,保证不出现栈溢出吗?

不能,只能延迟栈溢出的时间

分配的栈内存越大越好吗?

不是,它避免不了栈溢出等异常,而且会占用其他内存空间

垃圾回收是否会涉及到虚拟机栈?

不会,它只存在栈溢出或者OOM,因为栈只涉及到入栈和出栈,但不会GC

方法中定义的局部变量是否线程安全?

得具体问题具体分析,

如果只有一个线程可以操作该变量,则线程安全;

如果多个线程可以操作该变量,则线程安全;比如通过形参传入一个stringbuilder非安全对象,若其他线程再操作stringbuilder对象时,则可能会改变结果,造成线程不安全;

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

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

相关文章

Nacos2.3.0源码启动报错找不到符号com.alibaba.nacos.consistency.entity

一. 源码下载编译:找不到符号com.alibaba.nacos.consistency.entity 如果报错找不到符号com.alibaba.nacos.consistency.entity Nacos\consistency\src\main\java\com\alibaba\nacos\consistency\entity 这个包下没有相关的java文件,其实是我们没有编译…

Vue.js 双向数据绑定的具体实现代码(简洁版)

1、 执行初始化,对data执行响应化处理 先来一个构造函数:执行初始化,对data执行响应化处理 class Vue { constructor(options) { this.$options options; this.$data options.data; // 对data选项做响应式处理 observe(this.$data);…

Linux性能优化实践——CPU上下文

CPU上下文切换 Linux是一个多任务操作系统,它支持远大于CPU数量的任务同时运行。这些任务不是真正意义上的并行运行,而是系统在短时间内,将CPU轮流分配给它们,造成任务同时运行的错觉。 CPU需要知道任务从哪里加载,从…

使用 OpenVINO™ 转换和优化 YOLOv8

本教程还可以作为 Jupyter Notebook 提供,可以直接从 GitHub 克隆。请参阅安装指南,了解在 Windows、Linux 或 macOS 上本地运行本教程的说明。 Ultralytics 开发的 YOLOv8 算法是一种尖端、最先进的 (SOTA) 模型,旨在快速、准确且易于使用,使其成为各种物体检测、图像分割…

Cartoon头像 InsCode Stable Diffusion 美图活动一期

一. 简单介绍和活动地址 简单介绍 试用Stable Diffusion 模型生成优质人物好图,更简单地炼丹。 “InsCode是一个集成了在线IDE、在线AI编程、在线算力租赁、在线项目部署以及在线SD 模型使用的综合代码开发平台。不论你是初级软件工程师,还是AI大模型…

【Java】删除集合元素的正确与错误做法

错误做法 一、fori正序 list.remove(num) Test public void test031(){ ArrayList<Integer> list new ArrayList<>(); list.add(1); list.add(3); list.add(3); for (int i 0; i < list.size(); i) { Integer numlist.get(i); if(num3){ list.re…

数据集 VOC转YOLO格式

一、xml转换为txt import os.path import xml.etree.ElementTree as ET import os import random # class_names [palm, stone, scissor, awesome, heartB, OK, ROCK, one, swear, thanks, heartA, # heartC, good, bad, pray, call, take_picture, salute] c…

Java:缓冲流

1.缓冲流分类 2.字节缓冲流 原理:底层自带了长度为8192的缓冲区提高性能。 1.方法&#xff1a; public BufferedInputstream( Inputstream is)&#xff1a;把基本流包装成高级流&#xff0c;提高读取数据的性能。public BufferedOutputStream(OutputStream os)把基本流包装成…

【Java|基础篇】面向对象三大特性之继承(上)

文章目录 1. 前言2. 问题提出3. 什么是继承4. 继承的特点 1. 前言 继承是面向对象三大特性之一. Java的继承也是很复杂. 本篇文章先帮助大家理解继承的概念 2. 问题提出 先来看这两个类: Student类: public class Student {private String name;private int age;private S…

【技能实训】DMS数据挖掘项目-Day02

文章目录 任务3【任务3.1】实现日志实体类【任务3.2】创建日志业务类&#xff0c;实现日志信息的采集及打印输出【任务3.3】创建日志测试类&#xff0c;测试任务3.2中的程序&#xff0c;演示日志信息的采集及打印输出 任务4【任务4.1】物流实体信息类【任务4.2】创建物流业务类…

Slicer学习笔记(六十四) 关于3DSlicer的python脚本和编程

Slicer学习笔记(六十四) 关于3DSlicer的python脚本和编程 目标1. 软件结构2. 在Slicer中使用python控制台 简单的脚本模块示例3. 单独编写简单的脚本模块目标 1. 软件结构 Slicer应用程序架构 模块类型:c++可加载 模块类型:脚本加载 模块类型:CLI Slicer数据模型 MRML

SendGrid 无法注册,Create Account 按钮灰色无法点击

问题描述&#xff1a; 注册SendGrid的时候&#xff0c;账号密码都输好了&#xff0c;就是没办法点【Create Account】。 解释思路&#xff1a; 其实空白处有一个reCAPTCHA 验证码&#xff0c;但是被隐去了。所以我们的思路是如何让网页中的reCAPTCHA 验证码顺利显示出来。 问…

vue实现一个购物车全功能

效果图: 1.静态代码结构渲染 <div class"app-container" id"app"><!-- 顶部banner --><div class"banner-box"><img src"http://autumnfish.cn/static/fruit.jpg" alt"" /></div><!-- 面包…

了解个人所得税

文章目录 1 个人所得税1.1 前置知识&#xff08;一定多看几遍&#xff09;1.2 个人所得税计算 2 汇算清缴参考 1 个人所得税 1.1 前置知识&#xff08;一定多看几遍&#xff09; 首先我们要弄清楚几个概念&#xff1a; ① 应纳税所得额 综合所得额 - 免征 - 扣除 ② 综合所…

Selenium浏览器自动化测试框架简单介绍

目录 selenium简介 介绍 功能 优势 基本使用 获取单节点 获取多节点 节点交互 动作链 执行JavaScript代码 获取节点信息 切换frame 延时等待 前进和后退 cookies 选项卡管理 异常处理 选项卡切换 无头浏览器 selenium简介 介绍 Selenium [1] 是一个用于We…

VectorCAST软件的License 配置

一、配置 License 服务 进入 VectorCAST 安装目录&#xff08;默认为 C:\VCAST&#xff0c;如果在安装时修改了安装路径&#xff0c;在这里需要进入对 应的安装目录&#xff09;&#xff0c;找到 FLEXlm 文件夹&#xff0c;将 License 文件复制到 FLEXlm 文件夹下面。运行 lmt…

当你按下键盘A键

CPU 里面的内存接口&#xff0c;直接和系统总线通信&#xff0c;然后系统总线再接入一个 I/O 桥接器&#xff0c;这个 I/O 桥接器&#xff0c;另一边接入了内存总线&#xff0c;使得 CPU 和内存通信。再另一边&#xff0c;又接入了一个 I/O 总线&#xff0c;用来连接 I/O 设备&…

视图与索引的详细用法

视图与索引的详细用法 1.视图的主要作用包括&#xff1a;1.简化查询&#xff1a;2.数据安全性&#xff1a;3.数据抽象&#xff1a; 2.索引简介1.索引的作用主要有以下几个方面&#xff1a;1.快速定位数&#xff1a;2. 提高查询性能3.加速排序和连接操作4.维护数据完整性 3.索引…

文字和祝福语:创意的粒子效果网页(❤️好看好用❤️)HTML+CSS+JS

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

Flink DataStream之Union合并流

新建类 package test01;import jdk.nashorn.internal.runtime.regexp.joni.Config; import org.apache.flink.api.java.ExecutionEnvironment; import org.apache.flink.configuration.Configuration; import org.apache.flink.streaming.api.datastream.DataStream; import o…