JVM(Java Virtual Machine,Java虚拟机)内存模型是Java程序在运行时进行内存分配和管理的核心机制。它定义了Java虚拟机在执行Java程序时,将程序中的数据和代码存储到计算机内存中的方式和规则。JVM内存模型的主要组成部分包括堆(Heap)、方法区(Method Area)、程序计数器(Program Counter Register)、虚拟机栈(VM Stack)和本地方法栈(Native Method Stack)。
以下是对这些组成部分的详细解释:
1. 堆(Heap)
定义:堆是JVM管理的最大的一块内存区域,用于存储对象实例和数组。
特点:
堆区是线程共享的,所有线程都可以访问堆中的数据。
堆内存的大小可以通过启动参数(如-Xmx和-Xms)来调整。
堆内存区域按照垃圾分代收集的角度可以进一步划分为年轻代(Young Generation)和老年代(Old Generation),默认年轻代和老年代比例为1:2。年轻代又可以分为Eden区、From Survivor区和To Survivor区,默认比例为8:1:1。
当堆中没有足够的内存完成实例分配时,并且堆也无法再扩展时,JVM会抛出OutOfMemoryError异常。
调整大小:年轻代与老年代默认为1:2,可通过-XX:NewRatio参数修改,如-XX:NewRatio=4,即为1:4。
伊甸区和S0、S1区默认为8:1:1,可通过-XX:SurvivorRatio参数修改,如-XX:SurvivorRatio=6,通过监测发现设置,以后并不是6:1:1,这是因为Java堆的内存分配策略自动调整了,关闭内存分配策略:-XX:-UseAdaptiveSizePolicy。
2. 方法区(Method Area)
定义:方法区用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。其中静态变量,JDK7以后移入Java堆中,字符串常量池(JDK8移入Java堆中。
特点:
方法区也是线程共享的。
在JDK 8之前,方法区通常被称为永久代(PermGen space),但在JDK 8及以后版本中,永久代被元空间(Metaspace)所取代。
方法区的大小可以通过启动参数(如-XX:MaxMetaspaceSize)来设置。
当方法区无法满足新的内存分配需求时,JVM会抛出OutOfMemoryError异常。
调整大小:
永久代(JDK1.7)
-XX:PermSize : 永久代初始化内存,默认20.75M, -XX:PermSize=20m
-XX:MaxPermSize: 永久代最大内存,32位虚拟机默认64M, 64位默认82M,超出时会报java.lang.OutOfMemoryError:PermaGen space
元空间(JDK1.8)
-XX:MetaspaceSize:元空间初始化内存,默认是21M
-XX:MaxMetaspaceSize:元空间最大内存,默认是-1无限制。虽然使用直接内存,但是当无法再为Metaspace分配内存时,将会抛出java.lang.OutOfMemoryError: Metaspace
3. 程序计数器(Program Counter Register)
定义:程序计数器是线程私有的,用于存储线程当前执行的字节码指令的地址。分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖程序计数器完成。
特点:
程序计数器是唯一一个在《Java虚拟机规范》中没有规定任何OutOfMemoryError情况的区域。
它记录了线程执行的字节码指令的偏移量,是线程恢复执行时的重要信息。
4. 虚拟机栈(VM Stack)
定义:虚拟机栈是线程私有的,用于存储局部变量表、操作数栈、动态连接、方法出口等信息。
特点:
每个方法被调用时,JVM都会同步创建一个栈帧(Stack Frame)用于存储这些信息。
栈帧的入栈和出栈过程对应着方法的调用和返回。
如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈容量可以动态扩展但无法申请到足够的内存,将抛出OutOfMemoryError异常。
调整大小:虚拟栈的大小可以通过-Xss参数设置,默认单位是byte,也可以使用不区分大小写k,m,g作为单位(如-Xss1m)。
5. 本地方法栈(Native Method Stack)
定义:本地方法栈与虚拟机栈的作用非常相似,但它是为虚拟机使用到的本地(Native)方法服务。
特点:
本地方法栈也是线程私有的。
它与虚拟机栈的区别在于服务的对象不同:虚拟机栈为虚拟机执行Java方法(即字节码)服务,而本地方法栈则为虚拟机使用到的本地方法服务。
本地方法栈同样会抛出StackOverflowError和OutOfMemoryError异常。
综上所述,JVM内存模型通过堆、方法区、程序计数器、虚拟机栈和本地方法栈等组成部分,为Java程序提供了高效、灵活的内存管理机制。这些组成部分各有其特点和作用,共同保障了Java程序的稳定运行。
评论区