一、整体结构

1、基本描述

JVM内存结构是Java虚拟机在执行程序的过程中会将内存划分为不同的数据区域。分为3个区域:堆内存、方法区、栈。
细分来说:栈(虚拟机栈、本地方法栈)、程序计数器,这三者是线程私有的;方法区、堆 ,线程公有。

image.png

2、参数控制

image.png

-Xms设置堆的最小空间大小。 -Xmx设置堆的最大空间大小。 -XX:NewSize设置新生代最小空间大小。 -XX:MaxNewSize设置新生代最大空间大小。 -XX:PermSize设置永久代最小空间大小。 -XX:MaxPermSize设置永久代最大空间大小。 -Xss设置每个线程的堆栈大小。

二、分区域介绍

1、Java堆-Heap

一般情况下,Java Heap 是Java虚拟机所管理的内存中最大的一块,在虚拟机启动时,此内存区域的目的是存放对象实例。
Java Heap是垃圾收集器管理的主要区域,因此也被称为GC堆。从内存回收的角度看,由于现在的收集器采用的是分代收集算法,可以细分Heap为:新生代和老年代;再细致点:Eden空间、From Survivor空间、To Survivor空间等。
Java虚拟机规范规定:Java Heap可以分布在物理上不连续的内存空间,只要逻辑上是连续的即可。

如果在堆中没有完成实例分配,且堆无法扩展,将会抛出OutOfMemoryError异常。

2、方法区-Method Area

该区域用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。Java虚拟机规范把方法去描述为Java Heap的一个逻辑部分,但又有一个别名 Non-Heap(非堆),用于与Java Heap区分开。

常在HotSpot虚拟机上开发、部署程序的开发者,习惯把方法区被称为:永久代(Permanent Generation),本质上两者不等价,只是因为HotSpot虚拟机的设计团队把GC分代收集扩展到了方法区。

Java虚拟机规范对该区域限制非常宽松,可选择不实现垃圾回收。

同堆一样,会抛出OutOfMemoryError异常。

3、程序计算器-Program Counter Register

该区域是一块较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里,字节码解释器工作时通过改变计数器的值来选取下一条需要执行的字节码指令,分支、循环、调整、异常处理、线程恢复等都依赖计算器来完成。

Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现。为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。

如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Natvie方法,这个计数器值则为空(Undefined)。

此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域

4、JVM栈 - JVM Stacks

Java Virtual Machine Stacks,线程私有,生命周期与线程相同。JVM Stacks用来描述Java方法的执行:每个方法的执行都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等。每个方法被调用直至完成的过程,对应这一个栈帧在JVM Stacks中的入栈到出栈的过程。

局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不等同于对象本身,根据不同的虚拟机实现,它可能是一个指向对象起始地址的引用指针,也可能指向一个代表对象的句柄或者其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。

其中64位长度的long、double类型的数据会占用2个局部变量空间(Slot),其余数据类型占用1个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。

如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;
如果虚拟机栈可以动态扩展(当前大部分的Java虚拟机都可动态扩展,只不过Java虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛出OutOfMemoryError异常。

5、本地方法栈-Native Method Stacks

和JVM Stacks类似,但本地方发展为Native方法服务。有些虚拟机,如HotSpot讲两者合二为一。

FAQ

1、方法内新建的对象存在哪区域?

参考

1、JVM之内存结构图文详解
2、JVM内存结构和Java内存模型