JVM 的内存区域:JMM(内存管理)

发布于:2025-04-11 ⋅ 阅读:(44) ⋅ 点赞:(0)

JVM 内存结构总览(运行时内存结构)

JVM 在运行 Java 程序时,会将内存划分为多个区域,用于执行、存储类信息、对象、方法调用栈等。

按照 Java 虚拟机规范,JVM 的内存区域可以细分为 程序计数器虚拟机栈本地方法栈方法区 等。
在这里插入图片描述
其中 方法区 是线程共享的,虚拟机栈本地方法栈程序计数器 是线程私有的。

本地方法栈都说是本地了肯定就是线程私有,虚拟机栈既然是要执行一些方法那么肯定也是线程自己私有进行的,程序计数器是指当前执行到哪一步了肯定也是特有的;方法区存的是类的信息等等,堆存储的所有对象实例和数组,都是属于线程共享的内容。


各个区域的详细介绍

1、程序计数器(Program Counter)

  • 作用:记录当前线程正在执行的字节码指令地址,表示执行到哪一步。
  • 特点:每个线程都有一个(线程私有)
  • 意义:支持多线程间的上下文切换

2、虚拟机栈(JVM Stack)

Java 虚拟机栈的生命周期与线程相同。

当线程执行一个方法时,会创建一个对应的 栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息,然后栈帧会被压入栈中。当方法执行完毕后,栈帧会从栈中移除。

栈帧是 JVM 运行时栈的基本单位,存储方法执行所需的变量和计算结果,方法调用时入栈,执行完毕后出栈。
在这里插入图片描述

在这里插入图片描述


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

本地方法栈与虚拟机栈相似,区别在于虚拟机栈是为 JVM 执行 Java 编写的方法服务的,而本地方法栈是为 Java 调用本地(native) 方法服务的,由 C/C++ 编写。

在本地方法栈中,主要存放了 native 方法的局部变量、动态链接和方法出口等信息。当一个 Java 程序调用一个 native 方法时,JVM 会切换到本地方法栈来执行这个方法。

运用场景:

当 Java 应用需要与操作系统底层或硬件交互时,通常会用到本地方法栈。

比如调用操作系统的特定功能,如内存管理、文件操作、系统时间、系统调用等。

举例:System.currentTimeMillis() 就是调用本地方法来获取操作系统的当前时间。
在这里插入图片描述

再比如 JVM 自身的一些底层功能也需要通过本地方法来实现。像 Object 类中的 hashCode() 方法、clone() 方法等。
在这里插入图片描述

解释一下 native 方法:

Native 方法是在 Java 中通过 native 关键字声明的,用于调用非 Java 语言(如 C/C++)编写的代码。Java 可以通过 JNI(Java Native Interface)与底层系统、硬件设备、或高性能的本地库进行交互。

使用本地方法栈(Native Method Stack)的主要目的是与操作系统底层或硬件交互,而 native 方法通常使用 C/C++ 主要是为了更高效地访问底层资源。


4、堆(Heap)

堆被所有线程共享,在 JVM 启动时创建,主要存放所有 new 出来的对象实例。
在这里插入图片描述
Java 中“几乎”所有的对象都会在堆中分配,堆也是 垃圾收集器(GC) 管理的目标区域。

从内存回收的角度来看,由于垃圾收集器大部分都是基于分代收集理论设计的,所以堆也会被划分为 新生代老年代Eden空间From Survivor空间To Survivor空间 等。
在这里插入图片描述但随着 JIT 编译器 的发展和逃逸技术的逐渐成熟,“所有的对象都会分配到堆上”就不再那么绝对了。

JIT(Just-In-Time)编译器,即即时编译器,是 JVM(Java 虚拟机)中的动态优化组件,用于将字节码转换为机器码,提升 Java 代码的执行效率。

从 JDK 7 开始,JVM 已经默认开启逃逸分析了,如果某些方法里的对象无法逃逸(被方法体外使用)出去,那么对象可以直接在栈上分配内存,但是会逃逸的对象一定要分配到堆中,因为堆是公共的,而栈是私有的。


5、方法区/元空间(MetaSpace)

方法区并不真实存在,属于 Java 虚拟机规范中的一个逻辑概念,用于存储已被 JVM 加载的类信息、常量、静态变量、即时编译器编译后的代码缓存等。

在 HotSpot 虚拟机中,方法区的实现称为永久代(PermGen),但在 Java 8 及之后的版本中,已经被元空间(Metaspace)所替代。


变量存在堆栈的什么位置?

对于局部变量来说,它存储在当前方法的栈帧中的局部变量表中。当方法执行完毕,栈帧被回收,局部变量也会被释放。

栈帧是 JVM 运行时栈的基本单位

public void method() {
    int localVar = 100;  // 局部变量,存储在栈帧中的局部变量表里
}

对于静态变量来说,它存储在 Java 规范中的方法区中,也就是元空间(Metaspace)。

public class StaticVarDemo {
    public static int staticVar = 100;  // 静态变量,存储在方法区中
}

内存区域组成部分 共享/私有 作用
虚拟机栈 私有 线程开始执行一个任务时,会创建一个栈帧,其中包括局部变量等数据,压入栈内,当任务执行完毕过后弹出栈。
本地方法栈 私有 与虚拟机栈类似,不过会在需要和操作系统或底层硬件交互的时候使用,并且虚拟机栈使用的 Java,而本地方法栈使用的是 C/C++。
程序计数器 私有 表示当前程序执行到了哪一步。
方法区/元空间 共享 JVM 的虚拟逻辑概念,存储类信息、常量、静态变量、被 JVM 加载的代码缓存。
共享 主要存储 new 出来的对象实例。

网站公告

今日签到

点亮在社区的每一天
去签到