02|JVM内存模型

1. JVM整体结构及内存模型

在这里插入图片描述

1.1 类装载子系统

负责加载字节码文件并将其转换为可以执行的Java类。类加载器子系统包括三个主要的类加载器:Bootstrap ClassLoader(引导类加载器)、Extension ClassLoader(扩展类加载器)和 Application ClassLoader(应用程序类加载器)。它们负责从不同的位置加载类文件, 加载到Runtime data area 中的method area(方法区)

1.2 字节码执行引擎

负责执行Java字节码指令。执行引擎包括解释器和即时编译器。解释器逐条解释字节码指令并执行相应的操作,而即时编译器将字节码编译成本地代码以提高执行效率。

1.3 本地方法接口(Native Interface)

与native libraries(本地方法库)交互,是其他编程语言交互的接口。

1.4 运行时数据区(JVM内存模型)

包括方法区、堆、虚拟机栈、本地方法栈程序计数器。这些区域负责存储运行时数据,包括类的信息、对象实例、方法的局部变量和操作数栈等。

1.4.1 程序计数器

程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。在Java虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令(每执行完一个指令,字节码执行引擎会立刻动态的修改程序技术器中的值(因为是字节码执行引擎执行的,所以字节码执行引擎每执行完一行代码,会去修改程序计数器中的值)),它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
由于Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存
如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是本地(Native)方法,这个计数器值则应为空(Undefined)。此内存区域是唯一一个在《Java虚拟机规范》中没有规定任何OutOfMemoryError情况的区域,生命周期随着线程的创建而创建,随着线程的结束而死亡

1.4.2 JAVA虚拟机栈

与程序计数器一样,Java虚拟机栈(Java Virtual Machine Stack)也是线程私有的,它的生命周期与线程相同。栈会给每个线程分配一个私有的栈,其内部保存一个个的栈帧。虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接(在程序运行时将符号引用替换为直接引用(常量池中的内存地址),常量池是放在方法区中)、方法出口(存储的是主方法调用子方法的地址)等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
在《Java虚拟机规范》中,对这个内存区域规定了两类异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果Java虚拟机栈容量可以动态扩展,当栈扩展时无法申请到足够的内存会抛出OutOfMemoryError异常。
特点是FILO(先进后出),拿数据从栈顶拿;局部方法先执行完,执行完后,局部方法的局部变量内存空间全部释放掉(出栈)

1.4.3 堆

Java堆(Java Heap)是虚拟机所管理的内存中最大的一块,所有线程共享,在虚拟机启动时创建;
唯一目的就是存放对象实例,几乎所有的对象实例以及数据都在这里分配内存,new出来的对象存放在堆中;由于即时编译技术的进步,尤其是逃逸分析技术的日渐强大,栈上分配、标量替换优化手段已经导致一些微妙的变化悄然发生,所以说Java对象实例都分配在堆上也渐渐变得不是那么绝对了;
根据《Java虚拟机规范》的规定,Java堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的,这点就像我们用磁盘空间去存储文件一样,并不要求每个文件都连续存放。但对于大对象(典型的如数组对象),多数虚拟机实现出于实现简单、存储高效的考虑,很可能会要求连续的内存空间。
Java堆既可以被实现成固定大小的,也可以是可扩展的,不过当前主流的Java虚拟机都是按照可扩展来实现的(通过参数-Xmx和-Xms设定)。如果在Java堆中没有内存完成实例分配,并且堆也无法再扩展时,Java虚拟机将会抛出OutOfMemoryError异常。

堆分为年轻代(Eden, s0 和s1)(1/3)和老年代(2/3),配比是可以调的;
new出来的对象一般是放在堆中的Eden;
静态变量user是放在方法区中,但是它是new出来的对象,new出来的对象是放在堆中的,所以方法区中存储的是堆中user对象的内存地址;

为什么要STW?

因为如果不停止用户线线程,当你还在根据gc root往下找的时候,还没结束,此时如果用户线程结束了,那么整个堆空间都释放掉了,此时整个链路都是垃圾对象,那么这样的话GC并没什么作用,不可能在回去遍历一次,所以JVM直接STW。

1.4.4 方法区

JDK17以前方法区被称为永久代,1,8开始,使用元空间取代了永久代,元空间使用的是本地内存JVM内存之外的部分叫做本地内存);1.8之后元空间存放在堆外内存中;
方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
字符串常量池在JDK7的时候放到了堆空间中
方法区中的元空间直接用的是物理内存(内存条),默认初始值是21M,当类信息很大达到21M时,会触发full gc,回收堆和方法区
方法区容量自动扩容机制,假设初始full gc后发现并没有回收多少,下次触发full gc的灵界点的大小>21M,一般元空间设置为256/512M。一定要设置值,否则大量full gc。
与永久代最大的不同就是,如果不指定大小的话,随着更多类的创建,虚拟机会耗尽所有可用的系统内存。

1.4.5 本地方法栈

本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别只是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的本地(Native)方法服务
《Java虚拟机规范》对本地方法栈中方法使用的语言、使用方式与数据结构并没有任何强制规定, 因此具体的虚拟机可以根据需要自由实现它,甚至有的Java虚拟机(譬如Hot-Spot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法栈也会在栈深度溢出或者栈扩展失败时分别抛出StackOverflowError和OutOfMemoryError异常。

1.4.6 JVM执行引擎

JVM中的元空间确实包含了大量的元数据,这些元数据为运行时提供了关于类、方法和字段的重要信息。但为什么在有了这么丰富的元数据之后,JVM还需要保留字节码呢?
答案就在执行引擎。执行引擎是JVM的核心部分,它负责将字节码翻译为可以在特定硬件上运行的机器代码。但是,这并不是一次性的过程。为了提高性能,JVM会使用Just-In-Time (JIT) 编译技术,将“热点”代码段编译成机器代码,从而大大加速程序的执行速度
因此,尽管元数据为JVM提供了关于类和方法的大量信息,但字节码的存在是为了允许执行引擎进行即时编译优化。这个细节不仅揭示了JVM的优雅设计,也为我们展现了Java为什么能在保持跨平台特性的同时,还能提供出色的性能。

基本结构与组件
执行引擎是JVM中的一个核心组件,负责管理和执行Java字节码。它主要由以下部分组成:
在这里插入图片描述

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

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

相关文章

linux nasm汇编中调用printf不报错,但调用scanf报错。抛出了分段错误(核心转储)

当我写了如下汇编时 ; nasm -f elf64 -g -F dwarf charsin.asm ; gcc charsin.o -no-pie -o charsin ; ld -o eatclib eatclib.o ; gdb eatclib[SECTION .data]SPrompt db Enter string data, followed by Enter: ,0IPrompt db Enter an integer value, followed by Enter: ,1…

人工智能应用工程师职业技能提升如何考取,需要具备怎样的技能?

人工智能应用工程师是能够利用人工智能相关技术进行应用研发,并开展各类工作的从业人员统称。 人工智能应用工程师考试是对人工智能领域从业者的全面认证,共分为初级、中级、高级三个等级,分别对应了人工智能应用工程师未来发展的三个大致方向…

本地写的Bash脚本,Linux端运行报错:/bin/bash^M: bad interpreter: No such file or directory

背景 在本地写了个Bash Shell脚本,但上传到Linux端后加完权限执行时报错: (脚本名:script.sh) -bash: ./script.sh: /bin/bash^M: bad interpreter: No such file or directory 分析 这个错误通常是由于脚本文件的行…

SSL证书快过期了怎么办?

SSL(Secure Sockets Layer)证书是保障网站安全、确保用户数据加密传输的关键元素。当SSL证书接近其有效期限时,及时更换新证书至关重要,以免影响网站的安全性和用户体验。下面是一份详尽的指南,指导您分步有序地完成SS…

【笔记】:更方便的将一个List中的数据传入另一个List中,避免多重循环

这里是 simpleInfoList 集合&#xff0c;记为集合A&#xff08;传值对象&#xff09; List<CourseSimpleInfoDTO> simpleInfoList courseClient.getSimpleInfoList(courseIds);if(simpleInfoListnull){throw new BizIllegalException("当前课程不存在!");}这…

LeetCode 2581.统计可能的树根数目:换根DP(树形DP)

【LetMeFly】2581.统计可能的树根数目&#xff1a;换根DP(树形DP) 力扣题目链接&#xff1a;https://leetcode.cn/problems/count-number-of-possible-root-nodes/ Alice 有一棵 n 个节点的树&#xff0c;节点编号为 0 到 n - 1 。树用一个长度为 n - 1 的二维整数数组 edges…

能让薪资翻3倍的软件测试面试经验

前言 面试真题&#xff1a;3 轮技术面 HR 面 面试总共经历四轮的面试&#xff0c;三轮的技术面试和一轮的 HR 面试&#xff0c;共耗时 5 个小时以上。 一面&#xff08;组长面&#xff09; 上家公司项目以及团队的规模是怎么样的&#xff1f; 你负责的项目整体的流程是怎么样的…

基于ssm课程管理系统

基于SSM的课程管理系统的设计与实现 摘 要 当下&#xff0c;正处于信息化的时代&#xff0c;许多行业顺应时代的变化&#xff0c;结合使用计算机技术向数字化、信息化建设迈进。以前学校对于课程信息的管理和控制&#xff0c;采用人工登记的方式保存相关数据&#xff0c;这种以…

【bash】2、手把手实现一个 bash shell:多个机器批量执行 shell 命令,支持 ip 补全

文章目录 一、需求&#xff1a;多台机器批量远程执行 shell 命令1.1 业务需求拆解为脚本需求1.2 帮助函数&#xff1a;使用说明文档1.3 main 函数框架 二、功能&#xff1a;单机 sshp 执行2.1 fullip 函数&#xff1a;实现 ip 补全2.1.1 参数说明2.1.2 定义全局变量2.1.3 实现&…

Doccano 修复 spacy.gold 的bug

引言 最初只是想把Doccano标注的数据集转换成BIO(类似conll2003数据集)的标注格式&#xff1b; 摘要 可先阅读一下教程&#xff1a;【已解决】关于如何将Doccano标注的文本转换成NER模型可以直接处理的CoNLL 2003格式 装包:pip install doccano-transformer 报错信息 运行…

基于springboot+vue的中药实验管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

SpringBoot源码解读与原理分析(三十八)SpringBoot整合WebFlux(一)WebFlux的自动装配

文章目录 前言第13章 SpringBoot整合WebFlux13.1 响应式编程与Reactor13.1.1 命令式与响应式13.1.2 异步非阻塞13.1.3 观察者模式13.1.4 响应性13.1.5 响应式流13.1.6 背压13.1.7 Reactor13.1.7.1 Publisher13.1.7.2 Subscriber13.1.7.3 Subscription13.1.7.4 Processor13.1.7.…