首页 > 编程语言 >深入理解Java虚拟机 --- 运行时数据区

深入理解Java虚拟机 --- 运行时数据区

时间:2024-11-08 13:21:28浏览次数:6  
标签:Java 虚拟机 局部变量 --- 线程 方法 栈帧

程序计数器

每个线程都有自己的程序计数器(线程私有),它可以看作是当前线程所执行的字节码的行号指示器

在Java虚拟机的概念模型里,字节码解释器工作时就是通过改变计数器的值来选取下一条需要执行的字节码指令。

为什么程序计数器线程私有

主要是为了保证进程切换之后能够恢复到正确的执行位置。

Java方法 & 本地方法

如果执行的是Java方法,那么程序计数器记录的是正在执行的虚拟机字节码。

如果执行的是本地方法(C++方法),那么值为空。

虚拟机栈

由于跨平台性,Java的指令都是根据栈来设计。

优点:不依赖硬件,跨平台,指令集小,编译器容易实现。

缺点:性能下降,实现同样的功能需要更多的指令。

虚拟机栈解决了程序的运行问题,堆解决了数据的存储问题。

概念

每个线程在创建时都会创建一个虚拟机栈,其内部保存一个个栈帧,每调用一个方法,相应的就会生成该方法的栈帧。

生命周期

其生命周期和线程一样。

作用

主管Java程序的运行,它保存方法的局部变量、部分结果并参与方法的调用和结果返回。

栈的优点

  • 操作方便,只需要两个操作,入栈和出栈

  • 不存在垃圾回收问题

  • 栈是一种快速有效的分配存储方式,访问速度仅次于PC寄存器。

StackOverFlowError & OutOfMemoryError

如果线程所请求的栈深度大于虚拟机所允许的深度时

1、若支持虚拟机栈扩展,那么拓展到没内存时到最后就会报出OutOfMemoryError

2、若不支持扩展,那么会报出StackOverFlowError

StackOverFlowError发生时,整个程序会崩溃吗

SpringBoot采用了线程隔离机制,如果发生StackOverFlowError的线程是独立的、非关键的,可能不会造成程序的崩溃。

栈的存储单位-栈帧

栈中的数据都是以栈帧的格式存在,每个方法都各自对应着一个栈帧。

我们通常把虚拟栈的栈顶元素称为当前栈帧,与其对应的方法称为当前方法,定义这个方法的类就是当前类。

image.png

栈帧的出栈

栈帧出栈有两种可能:

  • 正常的函数返回,使用return指令

  • 抛出异常

栈帧的内部结构

每个栈帧都存储着:

  • 局部变量表

  • 操作数栈(或表达式栈)

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

局部变量表

也被称为局部变量数组或本地变量表。

定义

一个用来存储方法参数和方法体内局部变量的数字数组。数据类型包括各类基本数据类型、对象引用以及returnAddress类型。

相关知识

  • 局部变量表建立在线程之上,所以不存在数据安全问题。

  • 局部变量表所需要的容量大小是在编译期确定下来的。

  • 局部变量表中的变量只在当前方法调用中有效。随着方法栈帧的销毁而销毁。

  • 方法嵌套调用的次数由栈的大小决定。

局部变量表的存储单元-Slot(变量槽)

image.png

  • 在局部变量表里,32位以内的类型只占用一个slot(包括returnAddress类型),64位的类型(long和double)占用两个slot。

    • byte、short、char在存储前被转换为int;boolean也被转换为int,0表示为false,非0表示为true。
  • 参数值的存放总是在局部变量数组的index0开始,到数组长度-1的索引结束。

  • JVM会为局部变量表中的每一个Slot都分配一个访问索引,通过这个索引即可成功访问到局部变量表中指定的局部变量值。

  • 如果需要访问局部变量表中的一个64bit的局部变量值时,只需要使用前一个索引即可。(比如:访问long或double)

  • 如果当前帧是由构造方法或者实例方法创建的,那么该对象引用this将会存放在index为0的slot处,其余的参数按照参数表顺序继续排列。

  • 局部变量表中的slot是可以重复利用的,如果一个局部变量过了其作用域,那么在其作用域之后申明的新的局部变量就很有可能会复用过期局部变量的槽位,从而达到节省资源的目的。

public void test(){
  {
    int a = 0;
  }
  int b = 0;
}

// 此时b会复用a的槽位
  • 局部变量表中的变量是重要的垃圾回收根节点,只要被局部变量表中直接或间接引用的对象都不会被回收。

操作数栈

定义

也被称为表达式栈,具有先进后出的特性。

作用

  • 算术操作

  • 方法调用:调用一个方法时,先将方法的参数压入操作数栈,然后执行调用指令,方法的返回值会压入操作数栈。

  • 条件判断

总结:指令执行的临时存储、方法参数和返回值的传递、数据的加载和存储

相关知识

  • 主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间。

  • 操作数栈是JVM执行引擎的工作区,当一个方法刚开始执行时会创造一个新的栈帧,这个新栈帧的操作数栈是空的。

  • 每一个操作数栈都会拥有一个明确的栈深度用于存储数值,其所需的最大深度在编译器就定义好了,保存在方法的Code属性中,为max_stack的值。

  • 栈中的任意一个元素都是Java数据类型。

    • 32bit的占用一个栈单位深度

    • 64bit的占用两个栈单位深度

  • 操作数栈用出栈、入栈来完成数据访问。

  • 如果被调用方法带有返回值,那么会将返回值压入当前栈帧中的操作数栈。

栈顶缓存技术

技术解决的问题

由于操作数是存储在内存中的,因此频繁地执行内存读/写操作必然会影响执行速度。

定义

将栈顶元素全部缓存到CPU的物理寄存器中,以此降低对内存的读/写次数,提升执行引擎的执行效率。

动态链接

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

动态链接的作用:为了将这些符号转换为调用方法的直接引用。

常量池的作用:为了提供一些符号和常量,便于指令的识别。

方法的调用

在JVM中,将符号引用转换为调用方法的直接引用与方法的绑定机制相关。

  • 静态链接(早期绑定)

    被调用的目标方法在编译器可知,且运行期保持不变。

  • 动态链接(晚期绑定)

    被调用的目标方法在编译器确定不下来,要在程序运行期将调用方法的符号引用转换为直接引用,这种引用转换过程具备动态性。

非虚方法与虚方法

  • 非虚方法在编译期就确定,在运行时不可变。

  • 静态方法、私有方法、final方法、实例构造器、父类方法都是非虚方法。

  • 其他方法称为虚方法,其在运行时确定。

虚方法表

为了避免每次动态分派都要重新在类的方法元数据中搜索,因此JVM在类的方法区创建了虚方法表,每次在虚方法表查找即可。

虚方法的创建时机:在类加载的链接阶段被创建并初始化。

Java语言是静态类型语言,在Lamda表达式出现之后,有了一些动态类型语言的特性。

静态类型语言与动态类型语言

  • 静态类型语言是判断变量自身的类型信息

  • 动态类型语言是判断变量值的类型信息,变量没有类型信息,变量值才有类型信息。

  • 区别:静态类型语言在编译期就对类型进行检查,动态类型语言在运行期才对类型进行检查。

方法返回地址

方法返回地址:存放调用该方法的PC寄存器的值。

方法正常退出时:调用者的PC寄存器的值作为返回地址,即调用该方法的指令的下一条地址。

方法异常退出时:返回地址通过异常表来确认,栈帧一般不会保存此信息。

正常完成出口和异常完成出口的区别在于:通过异常完成出口退出的不会给他的上一层任何返回值。

本地方法栈

和虚拟机栈一样。

区别就是:虚拟机栈内存放的是Java方法的栈帧,本地方法栈内存放的是本地方法的栈帧。

所以这里就不过多赘述。

Java堆是虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块区域

几乎所有的对象实例都分配在这里。

TLAB(Thread Local Allocation Buffer)

原因

堆区是线程共享的区域,因为是共享的,在多个线程下,就会存在线程安全问题。所以就出现了TLAB来解决这个问题。

定义

从内存模型而不是垃圾回收的角度,对Eden区域继续进行划分,JVM为每个线程分配了一个私有缓存区域,它包含在Eden内。

多线程同时分配内存时,使用TLAB能够解决线程安全问题,同时也能提升内存分配的吞吐量,我们将这种内存分配方式称为快速分配策略。

一旦对象在TLAB空间分配内存失败时,JVM就会尝试使用加锁机制来确保数据的原子性。

image.png

方法区

尽管所有的方法区在逻辑上是属于堆的一部分,但一些简单的实现可能不会选择去进行垃圾回收或者压缩。方法区看作是一块独立于Java堆的内存空间。

永生代 & 元空间

JDK7之前把方法区叫永生代,JDK8之后把方法区叫元空间。

元空间与永久代最大的区别在于:元空间不在虚拟机设置的内存中,而是在本地内存。如果方法区无法满足新的内存分配要求,将抛出OOM异常。放在本地内存的话,能够保证内存比原先的虚拟机设置的内存多。

方法区的内部结构

方法区的内部存储内容:类型信息、常量、静态变量、即时编译器编译后的代码缓存。

类型信息

对每个加载的类型(类Class、接口Interface、枚举enum、注解annotation),JVM必须在方法区中存储如下信息:

  1. 这个类型的完整有效名称(全名=包名+类名)

  2. 这个类型直接父类的完整有效名(接口和Object没有)

  3. 这个类型的修饰符

  4. 这个类型直接接口的一个有序列表

域(Field)信息

域相关信息:域名称、域类型、域修饰符

方法(Method)信息

方法相关:

  1. 方法名称

  2. 方法返回的类型

  3. 方法的参数的数量和类型

  4. 方法的修饰符

  5. 方法的字节码、操作数栈、局部变量表及大小

  6. 异常表

标签:Java,虚拟机,局部变量,---,线程,方法,栈帧
From: https://www.cnblogs.com/ayu0v0/p/18534864

相关文章

  • 深入理解Java虚拟机 --- 垃圾标记/收集算法
    在开始本章之前,我们得了解一个概念,那就是我们怎么知道这个对象是"垃圾"?所以如何定义垃圾就成为我们第一个需要探讨的重要的点之一。垃圾标记算法常见的垃圾标记算法有:引用计数算法和可达性分析算法。引用计数算法实现思路每个对象去额外存储一个引用计数器,这个计数器统计了对......
  • 深入理解Java虚拟机 --- 垃圾回收器
    Serial收集器HotSpot虚拟机运行在客户端模式下的默认新生代收集器。类型:单线程串行垃圾回收器垃圾收集算法:复制算法作用区域:新生代特点:1、只会用单个线程去完成垃圾收集工作,用户线程会STW,直到收集结束。2、没有线程交互,专心做垃圾收集,获得最高的单线程收集效率。ParNew收......
  • 深入理解Java虚拟机 --- 内存分配与回收策略
    对象优先在Eden区分配大多数情况下,对象在Eden区进行分配。当Eden区没有足够的空间来进行分配时,就会触发YoungGC(MinorGC)。当触发YoungGC时,如果Survivor区不够放存活的对象,那么就会触发分配担保机制提前转移到老年代。大对象直接进入老年代大对象的问题:1、容易导致内存明......
  • 深入理解Java虚拟机 --- 类加载机制
    类的生命周期类的生命周期:加载→验证→准备→解析→初始化→使用→卸载类加载的时机关于在什么情况下需要需要开始类加载过程的第一个阶段"加载",虚拟机并没有进行强制约束,这点交给虚拟机的具体实现来自由把握。但严格规定了有且只有六种情况必须立即对类进行"初始化":(字节码......
  • 开源模型应用落地-glm模型小试-glm-4-9b-chat-tools使用(五)
    一、前言  GLM-4是智谱AI团队于2024年1月16日发布的基座大模型,旨在自动理解和规划用户的复杂指令,并能调用网页浏览器。其功能包括数据分析、图表创建、PPT生成等,支持128K的上下文窗口,使其在长文本处理和精度召回方面表现优异,且在中文对齐能力上超过GPT-4。与之前的GLM系列......
  • JavaLin第六章:JavaLin的访问管理和默认响应
    文章目录前言一、JavaLin的访问管理二、JavaLin的默认响应总结前言最近忙起来了,就没有更新了,实在不不好意思,最近会进行javalin的陆陆续续的更新,希望大家支持。在Java里面有很多框架,其中权限管理是一个非常重要的功能实现,对于每个用户设定该用户的角色,对应相应用户......
  • 复制下来就能跑:Java智能问答系统-介绍与代码实践 - 基于springboot_springai_国产大模
    本文的目的是在5分钟内能把智能问答系统的原理和实践讲明白代码可执行,复制粘贴即可,可以快速跑起来。智能问答系统简介智能问答系统是一种人工智能应用,它能够理解用户提出的问题,并通过自然语言处理技术来分析和理解问题的含义。随后,系统会在其知识库中搜索相关信息,以生成......
  • 庖丁解java(一篇文章学java)
    (大家不用收藏这篇文章,因为这篇文章会经常更新,也就是删除后重发) 一篇文章学java,这是我滴一个执念...当然,真一篇文章就写完java基础,java架构,java业务实现,java业务扩展,根本不可能.所以,这篇文章,就是一个索引,索什么呢?  请看下文...关于决定开始写博文的介绍......
  • 【补档】玄武550电源怎么样? - 约呼的回答 - 知乎
    【补档】玄武550电源怎么样?-约呼的回答-知乎约呼一个路过的图吧用户低预算整机非常推荐,高预算慎选。低预算整机非常推荐,高预算慎选。优点不少,缺点也有。先说优点:价格上来说便宜大碗,用料不错,部分型号反向虚标,比如550v4其实是按650w规格用料来做的,拆解视频一堆,相对透明,售......
  • MM--项目中遇到的一些问题记录
    采购订单:创建采购订单时,供应商对应的信息记录已失效,但是切换供应商之后价格不会自动更新成01.SU01-查看用户对应的采购缺省值  2.SPRO-维护采购缺省值 采购订单收货的时候,提示无符合条件的行项目经打断点发现是由于程序中判断时公司间的内部交易所导致的,根本原......