java基础-jvm内存模型

JVM(Java Virtual Machine,Java虚拟机)的内存模型(运行时数据区域)是其核心组成部分,用于管理程序运行过程中的各类数据。根据《Java虚拟机规范》,JVM的内存结构可分为以下6大区域(部分区域为线程私有,部分为线程共享):

一、程序计数器(Program Counter Register)

线程私有,是一块较小的内存空间,用于记录当前线程正在执行的字节码指令的行号(或Native方法的执行状态)。

  • 核心作用:当线程被切换时(如CPU时间片用完),程序计数器用于恢复线程的执行位置(类似“断点续跑”)。
  • 特性
    • 唯一不会抛出内存溢出(OOM)的区域;
    • 若当前线程执行的是Java方法,计数器存储的是字节码指令地址;若执行的是Native方法(如C/C++实现的本地方法),计数器值为undefined

二、Java虚拟机栈(Java Virtual Machine Stacks)

线程私有,每个线程在创建时会分配一个虚拟机栈,用于存储方法调用的栈帧(Stack Frame)

  • 栈帧结构:每个方法调用对应一个栈帧,包含:
    • 局部变量表:存储方法参数、局部变量(基本类型、对象引用);
    • 操作数栈:用于字节码指令的运算(如iadd指令需从操作数栈取两个数相加);
    • 动态连接:指向运行时常量池中该方法的引用(用于方法调用的动态绑定);
    • 方法出口:记录方法执行完毕后返回到上层方法的地址。
  • 异常场景
    • 若线程请求的栈深度超过JVM允许的最大值(如递归过深),抛出StackOverflowError
    • 若栈可动态扩展(如HotSpot默认固定大小),但扩展时无法申请到内存,抛出OutOfMemoryError(OOM)。

三、本地方法栈(Native Method Stacks)

线程私有,与虚拟机栈功能类似,但用于执行Native方法(如Java调用C/C++实现的方法,如Object.hashCode())。

  • HotSpot特性:HotSpot虚拟机直接将本地方法栈与虚拟机栈合并(统一管理)。

四、Java堆(Java Heap)

线程共享,是JVM管理的最大内存区域,所有对象实例(如new Object())和数组均在此分配内存。

  • 核心作用:Java堆是垃圾回收(GC)的主要区域,因此也被称为“GC堆”。
  • 内存划分(分代设计):为优化GC效率,堆通常分为:
    • 新生代(Young Generation):存放新创建的对象,分为:
      • Eden区(对象初始分配的主区域);
      • Survivor区(S0、S1,用于存放GC后存活的对象)。
    • 老年代(Old Generation/Tenured Generation):存放多次GC后仍存活的对象(如长生命周期的缓存对象)。
  • 异常场景:若堆内存不足且无法扩展,抛出OutOfMemoryError: Java heap space

五、方法区(Method Area)

线程共享,用于存储类的元数据(如类的结构、字段、方法、接口)、运行时常量池(Runtime Constant Pool)、静态变量static修饰的变量)等数据。

  • JDK版本差异
    • JDK7及之前:方法区用“永久代(PermGen)”实现,内存限制受JVM参数(如-XX:MaxPermSize)控制,且与堆共享内存;
    • JDK8及之后:方法区用“元空间(Metaspace)”实现,内存直接使用本地内存(不受JVM堆限制),参数改为-XX:MaxMetaspaceSize(默认无限制,可能导致本地内存溢出)。
  • 运行时常量池(Runtime Constant Pool)
    • 是方法区的一部分,存储编译期生成的字面量(如字符串、数字)符号引用(如类名、方法名)
    • 支持动态扩展(如String.intern()可将字符串添加到常量池)。

六、直接内存(Direct Memory)

非JVM规范定义区域,但被频繁使用(如NIO的ByteBuffer)。它通过UnsafeByteBuffer直接分配堆外内存(本地内存),避免了Java堆与本地内存的拷贝开销。

  • 异常场景:若本地内存不足,可能抛出OutOfMemoryError(常见于大量使用NIO的应用)。

关键总结:JVM内存模型 vs Java内存模型(JMM)

需注意区分两个易混淆概念:

  • JVM内存模型:本文讨论的“运行时数据区域”,关注内存的物理划分(如堆、栈、方法区);
  • Java内存模型(JMM,Java Memory Model):JVM定义的一组规则,用于规范多线程间的内存可见性原子性有序性(如通过volatilesynchronized实现),是逻辑模型而非物理区域划分。

附:JVM内存参数示例(JDK8+)

实际开发中,可通过JVM参数调整各区域大小(以HotSpot为例):

# 堆内存:最小256M,最大512M
-Xms256m -Xmx512m  

# 新生代大小:128M(Eden:S0:S1=8:1:1)
-XX:NewSize=128m -XX:SurvivorRatio=8  

# 元空间:最大256M(本地内存)
-XX:MaxMetaspaceSize=256m  

# 栈大小:每个线程栈1M(默认1M,减少可增加线程数)
-Xss1m  
posted on 2025-05-23 14:06  斜月三星一太阳  阅读(42)  评论(0)    收藏  举报