当前位置: 首页 > news >正文

堆、方法区、虚拟机栈、本地方法栈、程序计数器

文章目录

      • 一、先明确:核心概念的“规范”与“实现”
      • 二、各区域的“作用”与“核心关系”
        • 1. 堆(Heap):“对象的仓库”,线程共享
        • 2. 虚拟机栈(Stack):“线程的临时工作区”,线程私有
        • 3. 方法区(规范)与元空间(实现):“类的信息仓库”,线程共享
        • 4. 字符串常量池(String Constant Pool):“字符串的复用池”,位于堆中
      • 三、总结:用“仓库”类比各区域的关系
      • 关键区别与联系表


在JDK 8及以后的版本中,JVM内存模型发生了重要调整(如永久代被元空间取代、字符串常量池位置迁移等),我们可以从“规范定义”和“实际实现”两个层面,梳理栈、方法区、字符串常量池、元空间、堆的关系。

一、先明确:核心概念的“规范”与“实现”

JVM规范中定义了堆、方法区、虚拟机栈、本地方法栈、程序计数器5大内存区域,而“元空间”“字符串常量池”是具体实现中的“子区域”或“替代实现”,先厘清基础定义:

概念类型JVM规范中的概念JDK 8及以后的具体实现
线程共享区域仍是堆(存储对象实例,是JVM中最大的内存区域,线程共享)。
线程共享区域方法区(Method Area)元空间(Metaspace) 实现(替代JDK 7及以前的“永久代”),存储类元数据等。
线程私有区域虚拟机栈(VM Stack)仍为虚拟机栈(简称“栈”),每个线程私有,存储栈帧(局部变量、操作数栈等)。
子区域(特殊存储)字符串常量池从JDK 7开始迁移到堆中(JDK 8延续这一设计),不再属于方法区/元空间。

二、各区域的“作用”与“核心关系”

1. 堆(Heap):“对象的仓库”,线程共享
  • 作用:存储所有对象实例(如new Object()new String()创建的对象),以及字符串常量池(JDK 8及以后)。
  • 核心特点
    • 是JVM垃圾收集器(GC)的主要工作区域(大部分对象的创建和销毁都在这里);
    • 线程共享(多个线程可同时访问堆中的对象)。
2. 虚拟机栈(Stack):“线程的临时工作区”,线程私有
  • 作用:每个线程启动时创建一个虚拟机栈,内部由多个“栈帧”(Stack Frame)组成(每个方法调用时创建一个栈帧)。栈帧中存储:
    • 局部变量(如String str中的str,即对象的引用);
    • 操作数栈(执行字节码时的临时数据存储);
    • 方法返回地址等。
  • 与堆的关系:栈中的“局部变量”通常是堆中对象的引用。例如:
    String str = new String("test"); 
    
    • new String("test")创建的对象实例在堆中
    • 变量str是局部变量,存储在栈的栈帧中,其值是堆中对象的内存地址(即“引用”)。
3. 方法区(规范)与元空间(实现):“类的信息仓库”,线程共享
  • 方法区(规范):JVM规范定义的区域,用于存储“类的元数据”(如类的结构定义、方法代码、字段信息、常量池(非字符串常量,如整数常量、符号引用等))、JIT编译后的代码等。

  • 元空间(实现):JDK 8及以后对“方法区”的具体实现,替代了之前的“永久代”,核心区别是:

    • 永久代是堆的一部分(受JVM堆内存限制);
    • 元空间位于本地内存(Native Memory)(即操作系统分配给JVM进程的内存),不受JVM堆内存大小限制(但可通过-XX:MaxMetaspaceSize手动限制)。
  • 与堆的关系:堆中存在“Class对象”(每个类加载后会在堆中创建一个Class实例,如String.class),该Class对象中包含指向元空间中类元数据的引用。例如:
    当JVM加载String类时:

    • String类的元数据(如length()方法的定义、value字段的类型等)存储在元空间
    • 堆中会创建String.class对象,通过它引用元空间中的元数据,JVM通过这个引用实现“对象调用类方法/字段”(如str.length())。
4. 字符串常量池(String Constant Pool):“字符串的复用池”,位于堆中
  • 作用:存储字符串常量(如"abc"),避免重复创建相同字符串,实现复用(节省内存)。

  • 位置:JDK 7及以后迁移到堆中(JDK 8延续),不再属于方法区/元空间。

  • 与堆中其他对象的关系

    • 直接声明的字符串(如String s = "abc"):先检查字符串常量池,若存在则直接让s引用常量池中的对象;若不存在则在常量池创建并引用。
    • new String()创建的字符串(如String s = new String("abc")):会在堆中创建一个新对象,同时检查字符串常量池——若“abc”不存在,会先在常量池创建“abc”,然后堆中对象引用常量池中的“abc”(即堆中对象的value字段指向常量池的字符串数组)。

    示例:

    String s1 = "abc";       // s1直接引用堆中字符串常量池的"abc"
    String s2 = new String("abc");  // 堆中创建新对象,s2引用该对象;该对象引用常量池的"abc"
    

三、总结:用“仓库”类比各区域的关系

可以把JVM内存想象成一个“工厂”,各区域的关系如下:

  • :相当于“主仓库”,存储所有“成品对象”(包括普通对象和字符串常量池这个“字符串子仓库”)。
  • 虚拟机栈:相当于“工人的工作台”,每个工人(线程)有一个,台上的“工具”(局部变量)指向主仓库的成品,方便随时取用。
  • 元空间:相当于“设计图纸库”,存储“类的设计图纸”(类元数据),这些图纸不在主仓库(堆)里,而在工厂的“独立档案室”(本地内存)中。
  • 字符串常量池:是“主仓库(堆)里的一个货架”,专门存放常用的“字符串零件”,避免重复生产。

关键区别与联系表

区域位置存储内容线程共享性与其他区域的核心关联
JVM内存(非本地)对象实例、字符串常量池共享栈中引用指向堆中对象;堆中Class对象引用元空间元数据
虚拟机栈JVM内存(非本地)栈帧(局部变量、操作数栈等)私有(每个线程)局部变量引用堆中的对象
元空间(方法区实现)本地内存(操作系统)类元数据、JIT编译代码等共享堆中Class对象引用元空间中的类元数据
字符串常量池堆中字符串常量(如"abc")共享堆中new String()对象可能引用常量池中的字符串

通过这个梳理,能更清晰地理解各区域的职责和它们之间的联动关系~

http://www.lryc.cn/news/625911.html

相关文章:

  • RabbitMQ:SpringAMQP 多消费者绑定同一队列
  • Java配置文件
  • 第1章 React组件开发基础
  • 第10章 React应用测试
  • 我的SSM框架自学2
  • IDEA测试代码报java file outset source root异常
  • STM32-FreeRTOS快速入门指南(中)
  • 【软件安装】VScode介绍安装步骤及中文界面设置方法
  • 从数据孤岛到实时互联:Canal 驱动的系统间数据同步实战指南
  • Java 11中的Collections类详解
  • 正式签约 | OpenLoong 项目正式捐赠至开放原子开源基金会,成为全国首个具身智能方向孵化项目!
  • Vulkan笔记(十三)-帧缓冲区与命令池命令缓冲区
  • 使用 SemanticKernel 连接本地大模型 Ollama
  • 11.Ansible自动化之-内容集管理
  • 快手Klear-Reasoner登顶8B模型榜首,GPPO算法双效强化稳定性与探索能力!
  • 图像增强——灰度变换增强(线性,对数,指数)、空间滤波增强、频域增强、主成分/彩色合成增强(原理解释和代码示例)
  • FPGA 在情绪识别领域的护理应用(一)
  • Spring Boot应用实现图片资源服务
  • 电商数据分析可视化预测系统
  • gitlab、jenkins等应用集成ldap
  • Wireshark获取数据传输的码元速率
  • 【iOS】内存管理
  • implement libtime on Windows
  • 软件系统运维常见问题
  • STM32之beep、多文件、延迟、按键以及呼吸灯
  • 【数据结构】用堆解决TOPK问题
  • 服务器数据恢复—硬盘坏道离线导致raid崩溃的StorNext文件系统数据恢复案例
  • 深度学习-167-MCP技术之工具函数的设计及注册到MCP服务器的两种方式
  • 应用控制技术、内容审计技术、AAA服务器技术
  • Commons-io