参考文章:
1.JVM的初布认识
java内存是一个比较重要的概念,大多数
JVM将内存区域划分成Method Area(Non-Heap)(方法区)、Heap(堆)、Program Counter Register(程序计数器),VM Stack(虚拟机栈orjava方法栈),Native Method Stack(本地方法栈)。如下图所示:
GC作用区:方法区、堆
2
、各区域详解
(1)
java栈(java virtual Machine Stacks
):
线程私有,生命周期同线程;
存放数据分为:基本类型的变量
(java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、
部分的返回结果
以及
Stack Frame
,
非基本类型的对象在JVM栈上仅存放一个指向堆上的地址。
在Java虚拟机规范中,对这个区域规定了两种异常情况:
1、如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。
2、如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。
每个方法被执行的时候都会同时创建一个栈帧,栈它是用于支持续虚拟机进行方法调用和方法执行的
数据结构
。对于执行引擎来讲,活动线程中,只有栈顶的栈帧是有效的,称为当前栈帧,这个栈帧所关联的方法称为当前方法,执行引擎所运行的所有字节码指令都只针对当前栈帧进行操作。
栈帧用于存储局部变量表、操作数栈、动态链接、方法返回地址和一些额外的附加信息。在编译程序代码时,栈帧中需要多大的局部变量表、多深的操作数栈都已经完全确定了,并且写入了方法表的Code属性之中。
因此,一个栈帧需要分配多少内存,不会受到程序运行期变量数据的影响,而仅仅取决于具体的虚拟机实现。
补充说明:
局部变量表所需的内存空间在编译期间完成分配,即在Java程序被编译成Class文件时,就确定了所需分配的最大局部变量表的容量。当进入一个方法时,这个方法需要在栈中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。
操作数栈又常被称为操作栈,操作数栈的最大深度也是在编译的时候就确定了
(2)
本地方法栈(Native Method Stacks)
类似于虚拟机栈,虚拟机栈为虚拟机执行Java方法服务;本地方法栈为使用到的本地操作系(Native)方法服务。此区域用于存储每个native方法调用的状态。
(3)
Java堆(Heap):线程共享,虚拟机管理的内存中最大一块,存储对象及数组值。
Java中所有通过new创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收。由于
Java Heap是垃圾收集器管理的主要区域,也被称为“GC堆”。根据虚拟机规范规定,逻辑上连续,物理上可处于不连续的内存空间,无内存分配且堆无法扩展时,抛出OutOfMemoryError异常。
可参照下图 理解Heap结构:
对于堆,有几点需要注意: