深入理解 Java 虚拟机内存模型

引言

Java 虚拟机(JVM)是 Java 程序能够在不同操作系统上运行的基础,而 JVM 内存模型则是决定 Java 程序如何管理内存的核心。JVM 的内存结构是为了提供高效的资源管理、内存回收和线程安全设计的,其中的各个内存区域承担着不同的任务。

本文将详细讲解 JVM 内存模型中的几个重要部分,主要围绕 程序计数器 、方法区 、常量池 等内容进行深入分析,帮助读者理解 JVM 内存如何分配、管理和回收。

一、程序计数器的作用

程序计数器(Program Counter Register, PC)是 JVM 中每个线程私有的一块内存区域,它的主要作用是保存当前线程正在执行的字节码的地址。它标记着程序执行的 位置,也就是指向当前线程所执行的字节码指令。

为什么程序计数器是私有的?
  • 线程私有性:每个线程都有独立的程序计数器,因为每个线程的执行路径是独立的,程序计数器帮助 JVM 在多线程环境中记录每个线程的执行进度,确保线程间互不干扰。

  • 线程切换:当线程被挂起并切换时,程序计数器的值保存了当前的执行状态,当线程恢复执行时,程序计数器的值帮助线程继续执行正确的位置,保证程序的顺利运行。

二、方法区的执行过程

方法区的方法执行过程

方法区用于存储类的 类型信息 、常量 、静态变量 、字节码 等数据。当 JVM 执行方法时,执行过程包括以下几个步骤:

  1. 解析方法调用:当 Java 程序调用方法时,JVM 首先会解析方法调用,确定目标方法。

  2. 栈帧创建:方法调用时,JVM 会为该方法创建一个栈帧。栈帧包含了该方法的局部变量、操作数栈和返回地址等信息。

  3. 执行方法:JVM 执行方法内部的指令,更新栈帧中的数据。

  4. 返回处理:方法执行完毕后,返回值被放入栈帧中,方法返回,并且栈帧被销毁。

方法区的内容

方法区是 JVM 中存储类信息、常量、静态变量等数据的重要区域。具体内容包括:

  • 类信息:方法区存储了 JVM 加载的所有类的信息,包括类的结构、方法、字段等定义。

  • 常量池:类中的常量,如字符串常量和数值常量,存储在方法区的常量池中。

  • 静态变量:类的静态变量存储在方法区中。

  • 即时编译器编译后的代码:JVM 在执行时,会将热点代码编译为机器码并存储在方法区,供后续执行时使用。

  • 符号引用:类、方法、字段的符号引用存储在方法区,用于解析和访问相关数据。

这些数据有助于 JVM 在运行时加载、管理和访问类的相关信息。

三、String 的存储位置

String 保存在哪里?

在 Java 中,String 类型的对象有特定的存储方式:

常量池 :Java 的 字符串常量池 是为了优化内存使用和提升效率而设计的。字符串常量池存储了 Java 程序中使用的所有字符串字面值。在字符串常量池中,字符串对象是共享的,只有一个对象实例。

  • 存储方式 :如果在程序中出现相同的字符串字面量(例如 "abc"),它们会指向常量池中的同一对象。

new String("abc") 执行过程

当你执行如下代码时:

复制代码
String s = new String("abc");

JVM 会执行以下步骤:

创建 "abc" 字符串常量:

  • 如果 "abc" 字符串常量还没有存在于字符串常量池中,JVM 会将 "abc" 字符串添加到常量池中。
  • 如果 "abc" 字符串常量已经存在,JVM 直接使用常量池中的该字符串对象。

创建 new String("abc") 实例:

  • JVM 会创建一个新的 String 对象,并将 "abc" 字符串常量的引用传入该对象的构造方法中。

堆内存分配:

  • "abc" 常量会被存储在字符串常量池中。
  • new String("abc") 创建的 String 对象会在堆内存中分配内存空间。

因此,创建 new String("abc") 时,会在内存中创建 两个对象:

  • 一个是 "abc" 字符串常量对象(存储在常量池中)。
  • 另一个是 new String("abc") 实例对象(存储在堆中)。

总结

理解 JVM 的内存模型对 Java 开发者至关重要,特别是在高性能应用和内存管理方面。通过清晰的了解每个内存区域的作用,开发者可以更好地管理和优化内存的使用。

总结要点:

  • 程序计数器:每个线程都有自己的程序计数器,记录当前线程执行的字节码地址。

  • 方法区:存储类的相关信息、常量池、静态变量和编译后的字节码。

  • 堆内存与常量池:字符串常量池用于存储字符串常量,减少内存的重复分配。

  • new String("abc"):创建了两个对象,分别存储在常量池和堆内存中。

相关推荐
晒太羊的猫10 小时前
jvm面试题
jvm
夜之眷属13 小时前
Core dump 崩溃排查:JVM 宕机后,那份 core 文件怎么用 gdb 还原现场
java·运维·服务器·jvm
用户0942485680314 小时前
第31章:JVM字节码解释器与模板解释器源码路径
java·jvm
阿俊-全栈开发17 小时前
LikeShop 版本升级与备份:从旧版平滑迁移的完整步骤
jvm·数据库·oracle·开源·likeshop·likeshop开源商城
Nebula_g19 小时前
JavaSE加强:线程Thread(线程安全重点)
java·开发语言·jvm·算法·javase·技术栈
JAVA面经实录91719 小时前
Java高级后端 · 全套面试通关手册(线上故障排查)
java·jvm·面试
sibylyue21 小时前
SQLite 运行模式
java·jvm·sqlite
toooooop821 小时前
宝塔Python项目管理器:环境变量踩坑记录
java·jvm·python
佳児素花痴╮2 天前
线程知识点
java·开发语言·jvm
用户094248568032 天前
第29章:【OpenJDK中级篇综合实战】百万长连接网关的JVM稳定性工程
java·jvm