java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而建立和销毁。下面的图显示了虚拟机内存管理区域的划分。
我主要给这些区域划分为两类:共享区域和隔离区域,分别用颜色不同的来表示:灰色的为共享内存区域;白色的是隔离内存区域。
下面分别详细说明一下这些区域在jvm中的作用。
隔离区
程序计数器
程序计数器是分配最小的一块内存,他记录的是线程执行当前字节码的行号。字节码解释器就是通过它来获取下一条需要执行的指令,循环,分支,跳转,异常等功能都是需要程序计数器来完成的。
在多线程的环境下,每个线程都会有一个隔离区,其中程序计数器就包括在内,也就是说每个线程都会有一个自己的程序计数器。当一个线程抢到CPU的执行权限后,就是通过程序计数器来实现继续执行的。
jvm内存中只有这一个区域不会出现outofmemory的异常。
虚拟机栈
虚拟机栈也是线程特有的内存区域。他描述了java方法执行的内存模型,也就是说,执行java方法是怎么分配内存的,下面详细讲解一下。
java方法每次被执行都会被转化为一个栈帧进入虚拟机栈,随着方法执行结束,栈帧会出栈。
栈帧包括以下内容:
(1)局部变量表:基本数据类型(int,boolean等)、引用类型、返回类型。其中一个局部变量的空间为32位,如果是double和long,需要两个单位。
(2)操作数栈:是一个后入先出栈,需要对变量进行一系列的运算
(3)动态链接
(4)方法出口
后续还会深入了解栈帧,在这里就不详细说明了。
这块内存区域会出现两种异常:
(1)StackOverflowError:当线程请求的站深度大于虚拟机栈的深度就会出现此异常。通俗点说,虚拟机栈的深度为50k,但是有两个30k的栈帧入栈,这是就会出现这个异常
(2)OutOfMemoryError:虚拟机栈是可以扩展的,但是但超过了当前最大的内存限制。如最大内存限制1M,动态扩展时需要2M,那么就会出现这个异常。
本地方法栈
其实和虚拟机栈差不多,只不过虚拟机栈是为java方法服务的,而本地方法栈是为native方法服务的。同理抛出异常也是与虚拟机栈一样的原因。
共享区
堆
堆内存是jvm管理的最大一块内存区域,也是很重要的一块。堆内存被所有线程共享使用。几乎所有的实例对象都会存放在退内存中,所以也是垃圾收集管理器重点的管理对象,也成GC堆。
目前堆内存的大小是可以扩展的,通过-Xmx和-Xms来控制,当申请对内存不够并且无法扩展时,就会抛出outofmemory异常。
具体的堆内存细节我们后面再详细研究。
方法区
主要存放的是常量,方法区内有一个常量池没专门用来存放常量的。此内存区域还存放了是对象类型数据。