聊聊jvm的内存结构, 以及各种结构的作用

简介: 【10月更文挑战第27天】JVM(Java虚拟机)的内存结构主要包括程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和运行时常量池。各部分协同工作,为Java程序提供高效稳定的内存管理和运行环境,确保程序的正常执行、数据存储和资源利用。

JVM(Java 虚拟机)的内存结构主要由以下几个部分组成,每个部分都有其特定的作用:


1. 程序计数器(Program Counter Register)


  • 定义与位置
  • 程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。在 JVM 的概念模型中,字节码解释器工作时就是通过这个计数器的值来选取下一条需要执行的字节码指令。
  • 此区域是线程私有的,即每个线程都有自己独立的程序计数器,各个线程之间互不影响。
  • 作用
  • 字节码执行顺序控制:在多线程环境下,由于线程的切换等操作,需要精确记录每个线程当前执行到的字节码位置。程序计数器确保了线程被切换回来后能继续从上次暂停的地方开始执行,保证了线程执行的连续性和顺序性。
  • 支持分支、循环和跳转操作:在执行循环、条件判断(如 if - else 语句)和方法调用(涉及跳转)等操作时,程序计数器能准确跟踪指令执行流程,使程序按照预期的逻辑执行。


2. Java 虚拟机栈(Java Virtual Machine Stack)


  • 定义与位置
  • 与程序计数器一样,Java 虚拟机栈也是线程私有的。它的生命周期与线程相同,随着线程的创建而创建,线程的结束而销毁。
  • 虚拟机栈描述的是 Java 方法执行的内存模型,每个方法在执行时都会创建一个栈帧(Stack Frame),并将其压入栈中,方法执行完毕后栈帧弹出。
  • 栈帧结构和作用
  • 局部变量表(Local Variable Table)
  • 定义:是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。在编译期就确定了其大小,并且在方法执行期间不会改变。
  • 作用:提供了方法内部数据存储的基本单元,保证了方法执行过程中对变量的快速访问和操作,是方法执行的基础数据支撑。
  • 操作数栈(Operand Stack)
  • 定义:是一个后入先出(LIFO)栈,在方法执行过程中,字节码指令向操作数栈中写入和提取操作数。
  • 作用:作为字节码指令的操作数存储和运算的场所,许多字节码指令都需要操作数栈来完成数据的传递、运算(如加法、乘法运算)和方法调用等操作。
  • 动态连接(Dynamic Linking)
  • 定义:每个栈帧都包含一个指向运行时常量池的引用,用于支持方法调用过程中的动态连接。
  • 作用:在 Java 中,方法调用可能涉及到不同类中的同名方法(如接口实现类中的方法调用),动态连接机制通过运行时常量池来确定实际调用的方法,保证了方法调用的准确性。
  • 方法返回地址(Method Return Address)
  • 定义:当一个方法执行完毕后,需要知道返回的位置,这个返回位置就存储在方法返回地址中。
  • 作用:保证了方法执行完后程序流程的正确回归,使得方法调用后的后续操作能够正常进行,无论是返回值的传递还是程序执行流程的衔接都依赖于此。
  • 整体作用
  • 为 Java 方法的执行提供了一个基于栈的运行环境,通过栈帧的压入和弹出机制,实现了方法的调用和返回,以及方法内部数据的管理和操作。


3. 本地方法栈(Native Method Stack)


  • 定义与位置
  • 本地方法栈与 Java 虚拟机栈类似,也是线程私有的。它与 Java 虚拟机栈的区别在于,Java 虚拟机栈用于执行 Java 方法,而本地方法栈用于执行本地方法(Native Method),即使用非 Java 语言(如 C 或 C++)编写的、被 Java 代码调用的方法。
  • 作用
  • 为本地方法的执行提供内存空间和执行环境,保证本地方法能够在 JVM 环境中顺利运行。在调用一些操作系统底层功能或使用硬件相关资源时,往往需要通过本地方法来实现,本地方法栈为这些操作提供了支持。


4. Java 堆(Java Heap)


  • 定义与位置
  • Java 堆是 JVM 所管理的内存中最大的一块,它是被所有线程共享的一块内存区域,在 JVM 启动时创建。
  • 堆内存的主要用途是存放对象实例,几乎所有的对象实例都在这里分配内存(除了一些特殊情况,如对象逃逸分析后确定可在栈上分配的对象)。
  • 作用
  • 对象存储:作为对象的主要存储区域,Java 堆为 Java 程序中大量的对象实例提供了存储空间。无论是简单的自定义对象,还是复杂的集合对象、框架类对象等,都在堆中分配内存。
  • 内存管理和垃圾回收重点区域:由于堆内存中对象的动态生成和销毁,随着程序的运行,堆内存中的对象会逐渐增多,其中一些对象会变成垃圾(不再被引用的对象)。因此,堆是垃圾回收机制(Garbage Collection)的重点管理区域,通过垃圾回收算法来回收垃圾对象占用的内存,以保证堆内存的有效利用。


5. 方法区(Method Area)


  • 定义与位置
  • 方法区也是所有线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等。
  • 在 Java 8 之前,方法区是在堆中的一个独立的区域,称为永久代(Permanent Generation)。Java 8 及以后,方法区的实现被元数据区(Metaspace)取代,元数据区并不在堆中,而是使用本地内存(Native Memory)。
  • 作用
  • 类信息存储:存放类的全限定名、类的父类信息、类的实现接口信息、类的访问修饰符等,这些信息是 Java 虚拟机在运行过程中识别和处理类的依据。
  • 常量存储:运行时常量池(Runtime Constant Pool)是方法区的一部分,它存储了各种字面常量(如字符串常量、基本类型的常量值)和符号常量(如类和接口的全限定名、字段和方法的名称和描述符等)。在编译阶段,这些常量被收集到常量池,在运行时可被使用。
  • 静态变量存储:类的静态变量(如public static int num;)在类加载时就会被分配到方法区中,并且在整个类的生命周期内都存在,为类的静态行为和数据共享提供了支持。
  • 代码存储:存储经过即时编译器(Just - In Compiler,JIT)编译后的代码,这些代码可以在后续的运行中被直接调用,提高了程序的运行效率。


6. 运行时常量池(Runtime Constant Pool)


  • 定义与位置
  • 运行时常量池是方法区的一部分,但在逻辑上是一个独立的概念。它在类加载时根据类的常量池(Class Constant Pool)创建,用于存储类的字面常量和符号常量。
  • 作用
  • 常量存储和共享:在 Java 程序中,很多常量需要在运行期间被使用,如字符串常量。运行时常量池为这些常量提供了集中存储的场所,并且对于相同的字面常量(如多次出现的字符串 "Hello"),在池中只会存储一份,实现了常量的共享,节省了内存空间。
  • 支持动态链接和解析:在 Java 方法执行过程中,涉及到对类、字段和方法的引用时,需要通过运行时常量池来进行动态链接和解析。例如,当调用一个方法时,字节码指令会通过运行时常量池找到对应的方法符号引用,然后将其解析为实际的方法调用,保证了 Java 程序在运行时对类和方法的准确使用。


JVM 的内存结构各部分紧密协作,为 Java 程序的运行提供了稳定、高效的内存管理和运行环境,保障了 Java 程序的正常执行、数据存储和资源利用。

相关文章
|
6月前
|
Arthas 存储 算法
深入理解JVM,包含字节码文件,内存结构,垃圾回收,类的声明周期,类加载器
JVM全称是Java Virtual Machine-Java虚拟机JVM作用:本质上是一个运行在计算机上的程序,职责是运行Java字节码文件,编译为机器码交由计算机运行类的生命周期概述:类的生命周期描述了一个类加载,使用,卸载的整个过类的生命周期阶段:类的声明周期主要分为五个阶段:加载->连接->初始化->使用->卸载,其中连接中分为三个小阶段验证->准备->解析类加载器的定义:JVM提供类加载器给Java程序去获取类和接口字节码数据类加载器的作用:类加载器接受字节码文件。
557 55
|
19天前
|
存储 缓存 Java
我们来说一说 JVM 的内存模型
我是小假 期待与你的下一次相遇 ~
144 4
|
26天前
|
存储 缓存 算法
深入理解JVM《JVM内存区域详解 - 世界的基石》
Java代码从编译到执行需经javac编译为.class字节码,再由JVM加载运行。JVM内存分为线程私有(程序计数器、虚拟机栈、本地方法栈)和线程共享(堆、方法区)区域,其中堆是GC主战场,方法区在JDK 8+演变为使用本地内存的元空间,直接内存则用于提升NIO性能,但可能引发OOM。
|
7月前
|
Arthas 监控 Java
Arthas memory(查看 JVM 内存信息)
Arthas memory(查看 JVM 内存信息)
538 6
|
4月前
|
存储 Java 编译器
深入理解Java虚拟机--类文件结构
本内容介绍了Java虚拟机与Class文件的关系及其内部结构。Class文件是一种与语言无关的二进制格式,包含JVM指令集、符号表等信息。无论使用何种语言,只要能生成符合规范的Class文件,即可在JVM上运行。文章详细解析了Class文件的组成,包括魔数、版本号、常量池、访问标志、类索引、字段表、方法表和属性表等,并说明其在Java编译与运行过程中的作用。
108 0
|
10月前
|
存储 设计模式 监控
快速定位并优化CPU 与 JVM 内存性能瓶颈
本文介绍了 Java 应用常见的 CPU & JVM 内存热点原因及优化思路。
995 166
|
8月前
|
存储 缓存 算法
JVM简介—1.Java内存区域
本文详细介绍了Java虚拟机运行时数据区的各个方面,包括其定义、类型(如程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和直接内存)及其作用。文中还探讨了各版本内存区域的变化、直接内存的使用、从线程角度分析Java内存区域、堆与栈的区别、对象创建步骤、对象内存布局及访问定位,并通过实例说明了常见内存溢出问题的原因和表现形式。这些内容帮助开发者深入理解Java内存管理机制,优化应用程序性能并解决潜在的内存问题。
353 29
JVM简介—1.Java内存区域
|
7月前
|
存储 NoSQL Redis
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 +  无锁架构 +  EDA架构  + 异步日志 + 集群架构
|
8月前
|
缓存 监控 算法
JVM简介—2.垃圾回收器和内存分配策略
本文介绍了Java垃圾回收机制的多个方面,包括垃圾回收概述、对象存活判断、引用类型介绍、垃圾收集算法、垃圾收集器设计、具体垃圾回收器详情、Stop The World现象、内存分配与回收策略、新生代配置演示、内存泄漏和溢出问题以及JDK提供的相关工具。
JVM简介—2.垃圾回收器和内存分配策略
|
8月前
|
存储 设计模式 监控
如何快速定位并优化CPU 与 JVM 内存性能瓶颈?
如何快速定位并优化CPU 与 JVM 内存性能瓶颈?
200 0
如何快速定位并优化CPU 与 JVM 内存性能瓶颈?