JVM(Java虚拟机)内存模型定义了Java程序在运行时的内存结构和行为。它不仅是Java程序运行的基础,也是理解垃圾回收、多线程和性能调优的关键。
JVM内存模型的核心组成部分
方法区(Method Area)
作用:存储类的元数据(如类名、方法信息、字段信息、常量池等);
特点
所有线程共享;
在JDK 8之前,方法区通过永久代(PermGen)实现;在JDK 8及之后,方法区被元空间(Metaspace)取代。
相关参数
-XX:MetaspaceSize
:初始元空间大小;-XX:MaxMetaspaceSize
:最大元空间大小。
堆(Heap)
作用:存储对象实例和数组;
特点
所有线程共享;
是垃圾回收的主要区域;
分为新生代(Young Generation)和老年代(Old Generation):
新生代:存放新创建的对象,分为Eden区、Survivor区(From和To);
老年代:存放长期存活的对象。
相关参数
-Xms
:初始堆大小;-Xmx
:最大堆大小;-XX:NewRatio
:新生代与老年代的比例;-XX:SurvivorRatio
:Eden区与Survivor区的比例。
栈(Stack)
作用:存储方法的局部变量、操作数栈、动态链接和方法返回值;
特点
每个线程独享一个栈;
栈帧(Stack Frame)是栈的基本单位,每个方法调用对应一个栈帧。
相关参数
-Xss
:设置线程栈的大小。
本地方法栈(Native Method Stack)
作用:支持Native方法(如C/C++代码)的执行;
特点
与栈类似,但专门用于Native方法。
程序计数器(Program Counter Register)
作用:记录当前线程执行的字节码指令地址;
特点
每个线程独享一个程序计数器;
如果执行的是Native方法,程序计数器的值为空(Undefined)。
JVM内存模型的工作机制
对象的创建与回收
对象创建
对象通常在新生代的Eden区分配;
如果Eden区空间不足,会触发Minor GC。
对象晋升
经过多次Minor GC后仍然存活的对象会被晋升到老年代。
垃圾回收
新生代使用复制算法(Copying);
老年代使用标记-清除(Mark-Sweep)或标记-整理(Mark-Compact)算法。
方法调用与栈帧
方法调用
每次方法调用都会创建一个栈帧,栈帧包含局部变量表、操作数栈、动态链接和方法返回地址。
方法返回
方法执行完成后,栈帧被销毁,程序计数器恢复到调用者的位置。
多线程与内存模型
线程私有区域
每个线程独享栈、本地方法栈和程序计数器。
线程共享区域
堆和方法区是所有线程共享的,需要同步机制来保证线程安全。
实例
以下是一个常见的JVM参数设置示例:
java -Xms512m -Xmx2g -Xss256k -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:+UseG1GC -jar app.jar
-Xms512m
:初始堆大小为512MB;-Xmx2g
:最大堆大小为2GB;-Xss256k
:每个线程的栈大小为256KB;-XX:MetaspaceSize=128m
:初始元空间大小为128MB;-XX:MaxMetaspaceSize=256m
:最大元空间大小为256MB;-XX:+UseG1GC
:启用G1垃圾回收器。