【JVM】(一)深入理解JVM运行时数据区

文章目录

  • 一、JVM 运行流程
  • 二、虚拟机栈(线程私有)
  • 三、本地方法栈 (线程私有)
  • 四、方法区(元数据区)
  • 五、堆(线程共享)
  • 六、程序计数器(线程私有)


一、JVM 运行流程

JVM 是 Java 程序的运行基础和运行环境,同时也是 Java 实现 "一次编译,到处运行" 的关键所在。因此,深入了解 JVM 对于学习和理解 Java 编程语言是至关重要的,那么JVM 到底是如何运行的呢?

下面这张图片展示了 JVM 的基本运行过程:

JVM的执行过程涉及以下主要组成部分::

  1. Java 代码转换为字节码(.class文件):编写完成后的 Java 源代码需要通过 Java 编译器编译为字节码,生成 .class 文件,这些文件包含了 Java 程序的中间代码。

  2. 类加载器(ClassLoader):JVM 的类加载器负责将 .class 字节码文件加载到内存中的运行时数据区类加载器根据类的全限定名(Fully Qualified Name)查找并加载对应的字节码文件,并根据文件内容创建 Class 对象来代表这个类,以供后续的执行引擎调用

  3. 运行内存管理:JVM负责管理程序运行时的内存区域,主要包括以下几个区域:

    • 虚拟机栈(Java Virtual Machine Stacks):用于存储方法调用的栈帧,包含局部变量、操作数栈等。
    • 本地方法栈(Native Method Stacks):用于执行本地方法的栈。
    • 方法区(Method Area):存储类的结构信息、常量池、静态变量等。
    • 堆(Heap):存储对象实例和数组的内存区域。
    • 程序计数器(Program Counter):记录当前线程执行的字节码指令的地址或索引。
  4. 执行引擎(Execution Engine)执行引擎是 JVM 的核心组件之一,负责执行加载到内存中的字节码文件。执行引擎有两种方式执行字节码:

    • 解释执行逐条解释字节码指令并执行相应的操作。解释执行效率较低,但跨平台性好,适用于刚开始执行的代码段或是执行次数较少的代码段。
    • 编译执行将字节码编译成特定平台的本地代码,然后交由CPU执行。编译执行效率高,但需要额外的编译时间,适用于执行次数频繁的代码段。
  5. 本地方法库(Native Libraries):JVM 中的 Java 代码无法直接访问底层操作系统,因为字节码只是一套跨平台的指令集规范。当 Java 代码需要执行底层操作系统或与本地代码(如C、C++)进行交互的时候。就需要通过本地方法库来实现这些功能。本地方法库允许 Java 程序调用与操作系统相关的本地代码,从而实现整个程序的功能。

以上就是 JVM 的主要运行过程以及运行时涉及的组成部分,下文是对其中的运行时数据区的详细介绍。

二、虚拟机栈(线程私有)

虚拟机栈是 Java 线程私有的内存区域,用于存储线程的方法调用和局部变量等信息。虚拟机栈的生命周期和线程相同,虚拟机栈描述的是 Java 方法执行的内存模型:

  • 每个方法在执行的时候都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
  • 当方法结束的时候,响应的栈帧也会因为出栈而销毁。

虚拟机栈主要包含四个部分:

  1. 局部变量表用于存储方法的局部变量。在Java方法执行时,它会分配一块内存区域,用于存储方法参数和方法内部定义的局部变量。局部变量表的大小在编译期间就被确定,存储的数据类型包括基本数据类型和对象引用。
  2. 操作栈用于执行方法时的计算操作。Java虚拟机的字节码指令通常都是基于操作数栈进行运算的。当一个方法被调用时,会将参数值和返回值等压入操作数栈,在方法执行时,字节码指令会从操作数栈中取值进行计算。
  3. 动态链接用于指向运行时常量池中该栈帧所属方法的引用。在Java虚拟机的运行时常量池中,存放着每个类的方法的符号引用,动态链接将这些符号引用与实际内存地址进行关联。
  4. 方法返回地址用于指示方法的返回地址。当方法执行完成后,需要知道从哪里继续执行,方法返回地址就是用来记录返回的目标地址。

什么是线程私有:

  • 线程私有是指在多线程环境下,每个线程都拥有自己独立的内存区域,其他线程无法直接访问或修改该区域。线程私有内存中的数据对于每个线程都是独立的,互不影响。这种设计使得多线程程序可以同时执行,每个线程都能够独立地运行和维护自己的数据。
  • 在JVM中,虚拟机栈本地方法栈程序计数器是线程私有的内存区域。每个线程都有自己的虚拟机栈和本地方法栈,用于支持方法调用和执行,并且这些栈的数据对其他线程是不可见的。程序计数器也是线程私有的,每个线程都有自己的程序计数器,用于指示当前线程执行的字节码指令的地址或索引。线程的切换时,会保存和恢复程序计数器的值,以保证线程切换后能正确继续执行。
  • 其他共享内存区域如方法区(元空间)是线程共享的。堆用于存储Java对象实例和数组,方法区用于存储类的结构信息、常量池、静态变量等。多个线程可以共同访问堆和方法区的数据,因此在多线程环境下,需要通过同步机制来保护共享数据的一致性和正确性。
  • 内存区域按线程私有和共享的划分:

三、本地方法栈 (线程私有)

本地方法栈与虚拟机栈类似,也是 Java 线程私有的内存区域。它用于支持 Java 程序调用和执行本地方法(Native Method)。本地方法是使用其他语言(如C、C++)编写的方法,通过本地方法接口(JNI,Java Native Interface)与 Java 代码进行交互。本地方法栈和虚拟机栈在功能上也是类似的,但它们分别用于 Java 方法和本地方法的调用。

四、方法区(元数据区)

方法区是 Java 线程共享的内存区域,用于存储类的结构信息、常量池、静态变量、即时编译器编译后的代码等。在 JDK 8 及以前版本,方法区是永久代(Permanent Generation);而在 JDK 8 及以后版本,方法区被替换为元空间(Metaspace)。方法区的大小可以通过启动JVM 时的参数来设置。

在《Java虚拟机规范中》把此区域称之为 “方法区”,而在 HotSpot 虚拟机的实现中,在 JDK 7 时此区域叫做永久代(Permanent Generation),JDK 8 中叫做元空间(Metaspace)。

JDK 1.8 元空间的变化:

  1. 对于 HotSpot 来说,JDK 8 元空间的内存属于本地内存,这样元空间的大小就不在受 JVM 最大内存的参数影响了,而是与本地内存的大小有关。
  2. JDK 8 中将字符串常量池移动到了堆中。

运行时常量池:

运行时常量池(Runtime Constant Pool)是方法区的一部分,用于存放在编译期间生成的各种字面量和符号引用。它是在类加载过程中,由虚拟机根据字节码文件中的常量池表构建而成。

在运行时常量池中,主要包含两种类型的数据:

  1. 字面量

    • 字符串字面量:即Java程序中直接写的字符串值,例如:“Hello, Java”。在JDK 8中,字符串字面量被移动到堆中,这样它们也可以被垃圾收集器回收,避免了一些内存问题。
    • final常量:在编译期间可以确定的final常量,例如:final int MAX_VALUE = 100;
    • 基本数据类型的值:例如:整数、浮点数、字符等基本数据类型的字面量。
  2. 符号引用
    符号引用是一种在编译期间产生的、但在类加载阶段需要用到的一种数据结构,它用于描述被引用的目标。符号引用包括:

    • 类和接口的完全限定名:例如:java.lang.String
    • 字段的名称和描述符:用于描述字段的名称和数据类型,例如:int count
    • 方法的名称和描述符:用于描述方法的名称和参数列表以及返回值类型,例如:void print(String message)

运行时常量池在类加载后,会存放在方法区中,并且在整个类的生命周期中存在,与类本身一起被回收。它在程序运行时提供了常量池解析、动态链接、方法调用等功能,为 Java 程序的执行提供了必要的支持。

五、堆(线程共享)

堆(Heap)是 Java 虚拟机中的一个运行时数据区域,用于存储Java对象实例和数组。堆是JVM中最大的一块内存区域,也是唯一被所有线程共享的内存区域。

在Java程序运行过程中,当使用new关键字创建对象时,对象实例会被分配在堆中。同时,数组也是对象,因此数组的元素也会存储在堆中。堆的大小可以在启动 JVM 时通过参数来指定,也可以动态调整(如果未指定大小,则JVM会根据系统内存自动设置初始大小)。

堆的主要特点包括:

  1. 线程共享:堆是所有线程共享的内存区域。所有线程都可以访问堆中的对象实例,这使得多个线程可以共同操作和共享对象。

  2. 动态分配和回收:堆的大小在程序运行时是可以动态调整的。当创建对象时,JVM会自动分配堆中的内存空间。当对象不再被引用时,垃圾收集器会自动回收堆中不再使用的对象的内存。

  3. 垃圾回收:堆中的内存由垃圾收集器负责管理。垃圾收集器会周期性地检查堆中的对象,将不再被引用的对象标记为垃圾,然后回收这些垃圾对象的内存,释放给堆供其他对象使用。

  4. 自动内存管理:Java 中的堆内存由 JVM 自动进行内存管理,程序员不需要手动释放内存。JVM 会自动进行垃圾回收,释放不再使用的内存,避免了内存泄漏等问题。

另外,在Java虚拟机的堆内存中,通常被划分为两个主要区域:新生代(Young Generation)老生代(Old Generation)

  1. 新生代(Young Generation)
    新生代是存放新创建的对象的区域。在新生代中,通常会将堆内存划分为一个Eden空间和两个Survivor空间(通常称为S0和S1)。新创建的对象首先会被分配到Eden空间。当Eden空间满时,会触发Minor GC(Young GC),垃圾回收器会将Eden空间和其中还存活的对象复制到一个未使用的Survivor空间中。然后,垃圾回收器会清除Eden空间和正在使用的Survivor空间,将其中的垃圾对象回收。幸存下来的对象会被晋升到老生代。

  2. 老生代(Old Generation)
    老生代是存放长时间存活的对象的区域。老生代中存放的对象通常是在新生代经过一定次数的Minor GC后仍然存活的对象,或者是大对象等。当老生代空间满时,会触发Major GC(Full GC),垃圾回收器会对整个堆进行回收,包括新生代和老生代的所有对象。

通过将堆内存分为新生代和老生代,并采用不同的垃圾回收策略,可以提高垃圾回收的效率。新生代中的Minor GC频繁进行,回收生命周期短的对象,尽可能快速地释放内存;而老生代中的Major GC则相对较少进行,回收生命周期长的对象,保证了老生代的稳定性和可靠性。

六、程序计数器(线程私有)

程序计数器也是 Java 线程私有的内存区域。它是一种指示器,用于指示当前线程执行的字节码指令的地址或索引。在Java线程切换时,程序计数器的值会被保存和恢复,以保证线程切换后能正确继续执行

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

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

相关文章

React性能优化之Memo、useMemo

文章目录 React.memo两种方式参数应用场景 拓展useMemouseMemo(calculateValue, dependencies) 参考资料 React.memo React 的渲染机制,组件内部的 state 或者 props 一旦发生修改,整个组件树都会被重新渲染一次,即时子组件的参数没有被修改&…

华为华三思科 交换机基础配置一览

console密码修改 华为 user-interface console 0 authentication-mode password set authentication password cipher XXXXXXXXX华三 line aux 0 authentication-mode password set auth pass simple XXX思科 en configure terminal line console 0 password 123 login忘记…

TypeScript基础学习

目录 一、安装 1、下载国内镜像 2、安装 3、查看安装情况 4、使用例子 二、变量声明 1、规则 2、声明的四种方式 3、注意 4、类型断言 5、类型推断 6、变量作用域 三、基础类型(共11种) 1、Any 类型 2、Null 和 Undefined 3、never 类型…

【备战csp-j】 csp常考题型详解(2)

二.计算机网络。 1. TCP/IP 协议共有( )层协议 。 A.3 B.4 C.5 D.6 答案:B 解析: 2.Ipv4 地址是由( ) 位二进制数码表示的。 A.16 B.32 C.24 D.8 答案:B 解析:IP地址是IP协议提供的一种统一的地址格式。在目前使用的IPv…

Linux - 进程控制(进程替换)

0.引入 创建子进程的目的是什么? 就是为了让子进程帮我执行特定的任务 让子进程执行父进程的一部分代码 如果子进程想执行一个全新的程序代码呢? 那么就要使用 进程的程序替换 为什么要有程序替换? 也就是说子进程想执行一个全新的程序代码&a…

k8s概念-Job和CronJob

回到目录 Job 对于非耐久性任务,比如压缩文件,任务完成后,pod需要结束运行,不需要pod继续保持在系统中,这个时候就要用到Job。 Job负责批量处理短暂的一次性任务 (short lived one-off tasks),即仅执行一…

关于Linux中前端负载均衡之VIP(LVS+Keepalived)自动化部署的一些笔记

写在前面 整理一些 LVS 相关的笔记理解不足小伙伴帮忙指正 傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来…

HCIP OSPF+BGP综合实验

题目 1、该拓扑为公司网络,其中包括公司总部、公司分部以及公司骨干网,不包含运营商公网部分。 2、设备名称均使用拓扑上名称改名,并且区分大小写。 3、整张拓扑均使用私网地址进行配置。 4、整张网络中,运行OSPF协议或者BGP协议…

Vue的标签<i>

在 Vue 中&#xff0c;<i> 标签用于表示图标&#xff08;Icon&#xff09;。它通常与图标字体或矢量图标库配合使用&#xff0c;用于展示不同的图标。<i> 标签是语义化的&#xff0c;用于表示图标的意义&#xff0c;而不仅仅是装饰性的。 在 Vue 中使用 <i>…

python森林生物量(蓄积量)数据处理到随机森林估算全流程

python森林生物量&#xff08;蓄积量&#xff09;估算全流程 一.哨兵2号获取/处理/提取数据1.1 影像处理与下载采用云概率影像去云采用6S模型对1C级产品进行大气校正geemap下载数据到本地NDVI 1.2 各种参数计算&#xff08;生物物理变量、植被指数等&#xff09;LAI&#xff1a…

网络空间安全及计算机领域常见英语单词及短语——网络安全(一)

目录 网络空间安全常见英语单词没事儿读着玩儿相关知识扫盲 CSDN的小伙伴们&#xff0c;我快回来咯&#xff01;网络空间安全常见英语单词 Cybersecurity 网络安全Network security 网络安全Information security 信息安全Data protection 数据保护Threat analysis 威胁分析Ri…

抖音引流推广的几个方法,抖音全自动引流脚本软件详细使用教学

大家好我是你们的小编一辞脚本&#xff0c;今天给大家分享新的知识&#xff0c;很开心可以在CSDN平台分享知识给大家,很多伙伴看不到代码我先录制一下视频 在给大家做代码&#xff0c;给大家分享一下抖音引流脚本的知识和视频演示 不懂的小伙伴可以认真看一下&#xff0c;我们…

【C++】总结9

文章目录 C从源代码到可执行程序经过什么步骤静态链接和动态链接类的对象存储空间C的内存分区内存池在成员函数中调用delete this会出现什么问题&#xff1f;如果在类的析构函数中调用delete this&#xff0c;会发生什么&#xff1f; C从源代码到可执行程序经过什么步骤 预处理…

印花税的本质和底层逻辑是什么?印花税降低是利好股市吗?

内容由LLM协助生成&#xff1a; 印花税是一种对特定交易或证券交易征收的税费&#xff0c;由政府机构收取。其本质和底层逻辑可以归结为以下几点&#xff1a; 资金来源&#xff1a;印花税是国家财政收入的一部分&#xff0c;用于满足政府的财政需求和公共支出。政府通过征收印花…

java学习路程之篇六、进阶知识、常用API、Arrays工具类、冒泡排序、选择排序、二分查找、正则表达式

文章目录 1、Arrays工具类2、冒泡排序3、选择排序4、二分查找5、正则表达式 1、Arrays工具类 2、冒泡排序 3、选择排序 4、二分查找 5、正则表达式

SQL UNION 操作符

UNION 操作符用于合并两个或多个 SELECT 语句的结果集。 请注意&#xff0c;UNION 内部的每个 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时&#xff0c;每个 SELECT 语句中的列的顺序必须相同。 SQL UNION 语法 SELECT column_name(s) FROM table1 …

Springboot MongoDB 事务

从版本4开始&#xff0c;MongoDB支持 事务。事务是建立在 会话之上的&#xff0c;因此&#xff0c;需要一个活跃的 ClientSession。 除非你在你的应用程序上下文中指定一个 MongoTransactionManager&#xff0c;否则事务支持是 DISABLED&#xff08;禁用的&#xff09;。你可以…

【Maven】Nexus3上传maven依赖jar

后端依赖 上次说到前端的批量tgz文件上传私服&#xff0c;其实服务端也有类似情况&#xff0c;我们有个私服也需要进行上传到私服&#xff0c;这里做个记录。因为上次有个小细节没注意白白传错了一遍&#xff0c;这里重新记录总结一下。 # 查看一下结构 $ tree -L 2 . |-- re…

【vue】 Tinymce 富文本编辑器 不想让上传的图片转换成base64,而是链接

前言&#xff1a;最近项目上需要使用富文本编辑器&#xff0c;觉得tinymce很不错就用了&#xff0c;具体怎么在项目中使用参考 【vue】 vue2 中使用 Tinymce 富文本编辑器 【vue】 Tinymce 数据 回显问题 | 第一次正常回显后面&#xff0c;显示空白bug不能编辑 这两天又遇到了…

Windows下RocketMQ的启动

下载地址&#xff1a;下载 | RocketMQ 解压后 一、修改runbroker.cmd 修改 bin目录下的runbroker.cmd set "JAVA_OPT%JAVA_OPT% -server -Xms2g -Xmx2g" set "JAVA_OPT%JAVA_OPT% -XX:MaxDirectMemorySize15g" set "JAVA_OPT%JAVA_OPT% -cp %CLASSP…