JAVA运行时区域(JVM)
JVM大致可分为五个区域:程序计数器,虚拟机栈,本地方法栈,堆,方法区。

1、程序计数器(Program counter register):是一块较小的内存区域,它可以看作是当前程序执行的字节码的行号的指示器。由于java虚拟机的多线程是通过时间片轮转切换并分配处理执行时间的方式来实现的,在任何的时刻,一个处理器只会执行一条程序的指令,为了线程之间的转化能够恢复的之前执行的位置,每条线程都应该有自己独立的程序计数器,各个线程之间的程序计数器是互不影响的,独立存储,称之为线程私有的内存。
2、java虚拟机栈(JAVA Virtual Machine Stachs):和程序计数器一样,也是线程私有的,它的生命周期和线程一样,每个方法执行的同时就会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息,每个方法从调用到执行完成,就对应一个栈帧在虚拟机栈中入栈到出栈的过程。JAVA虚拟机规范中,这个区域规定了两个异常:
2.1:如果线程请求的深度大于虚拟机栈所允许的深度,将抛出StackOverflowError异常;
2.2:如果虚拟机栈动态扩容,扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常;
3、本地方法栈:本地方法栈和虚拟机栈一样,也是线程私有的,所发挥的作用也非常的类似,只不过是虚拟机栈为虚拟机执行java方法服务,本地方法栈为虚拟机使用native方法服务。和虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError异常和OutOfMemoryError异常。
4、堆(Heap):堆是JAVA虚拟机所管理的内存中最大的内存区域,是所有线程共享的内存区域,在虚拟机启动创建中,此内存的唯一目的就是存放对象的实例,几乎所有的对象实例都存放在这里。JAVA堆也是收集器管理的重要的区域,很多的时候也被称为GC堆,JAVA堆可以细分为:年轻代和老年代。在细致一点有:Eden空间,From Survivor空间,To Survivor空间;无论怎么划分,都与存放的位置无关,无论在那个区,对象仍然需要实例,进一步划分的原因,是为了更好的回收内存,或者是更快的分配内存。堆也是可扩展的,主流的虚拟机通过-Xmx和-Xms控制,如果堆中没有内存完成实例分配,将会抛出OutOfMemoryError异常;
5、方法区(Method Area):方法区和堆一样,是线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即编译器编译后的代码等数据,Java虚拟机规范把方法区描述为堆的一个逻辑部分,即非堆(Non-Heap),目的为了和堆划分开,Java虚拟机规范对方法区的限制是非常宽松的,除了和java堆一样,不需要连续的内存区域,可以选择固定大小或者可扩展性,还可以选择不实现垃圾收集。垃圾收集在这个区域是很少出现的,当方法区无法满足内存分配需求的时候,将会抛出OutOfMemoryError异常;
------------------------------------------------------------------------
直接内存:直接内存并不是虚拟机运行数据的一部分,也不是java虚拟机定义的内存区域。但是这块内存也会被频繁的用到,而且也会导致OutOfMemoryError异常的出现。在JDK1.4k新加入的NIO的模式,引入一种基于通道(Channel)和缓冲池(Buffer)的I/O的方式,可以是Native函数库直接分配堆外内存,这样能在一些场景中提高性能,直接内存的分配不会受到java堆大小的限制,但是会受到本机的内存限制,如果说内存限制大于本机内存大小,也会抛出OutOfMemoryError异常;

浙公网安备 33010602011771号