(1) Java的运行时数据区域

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,一般来说,包含下面几个


其中绿色部分是由所有线程共享的数据区,橙色部分是线程隔离的数据区。

1.程序计数器

程序计数器是一块比较小的内存空间,可以看成是当前线程所执行的字节码的行号指示器。也就是用来标识当前线程执行到哪个地方,所以线程隔离就理所当然。Java虚拟机的多线程是各线程轮换执行的,所以,为了能恢复到某个线程正确的执行位置,线程计数器是有必要的。

另外如果是执行的一个Java方法,计数器记录的是正在执行的虚拟家字节码指令的地址;如果执行的本地(native)方法,因为本地方法在只要要用C实现,这个计数值是为空的。

计数器区域是唯一一个没有规定OutOfMemoryError异常的区域。

2.Java虚拟机栈

虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行时都会创建一个栈帧(Stack Frame),用来存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法在从调用到执行完的过程,就对应一个栈帧在虚拟机栈中入栈到出栈的过程。

Java虚拟机栈也是线程私有的,每个线程在执行时有独立的栈空间。

一般在讲虚拟机内存时容易分为堆和栈,此时的栈差不多是讲的虚拟机栈的局部变量表。局部变量不存放了基本的数据类型以及对象的引用(reference)用来指向对象或者是对象的句柄。

虚拟机规范中对与该区域规定了两个异常,StackOverflowError异常和OutOfMemoryError异常。前者是请求的栈深度大于虚拟机允许的深度。后者是因为虚拟机栈扩展时无法申请到足够的内存

3.本地方法栈

与虚拟机栈类似。区别在于Java虚拟机栈为Java方法服务,而本地方法栈为本地方法及被Native修饰的方法服务

本地方法栈也会抛出StackOverflowError异常和OutOfMemoryError异常。

4.Java堆

Java堆用来存放对象实例和数组,因此是所有的内存中最大的一块,因为对象一般是线程间共用的,堆空间也是线程共享的。

堆空间可以划分的更细,但存放的内容和划分区域无关,都是对象,知识为了更好的回收或者分配内存,譬如分为新生代和老年代等,

堆空间可以物理上不连续,只要逻辑上连续即可,同样,堆空间没有完成实例分配,并且无法扩展时,也会抛出OutOfMemoryError异常。

5.方法区

方法区用于存储已经被虚拟机加载的类信息,常量、静态变量等。同样因为存储的信息不是线程私有的,方法区内存也是线程共享的。

方法区无法满足内存分配需求时,也会抛出OutOfMemoryError异常。

6.运行时常量池

运行时常量池是方法区的一部分,用于存放编译器生成的各种字面量和符号引用,譬如生成的String

另外运行时生成的新的常量也可以再放入常量池,譬如String类的intern()方法,就是将新的字符串放入常量池

因为常量池是方法区的一部分,因此在内存不够时也会抛出OutOfMemoryError异常。

7.直接内存

最后,不管各部分内存怎么分配,总和受本机物理内存的限制,所以再分配内存时也要注意本机RAM等的限制,各区域内存总和大于物理内存时也会报OutOfMemoryError异常。

猜你喜欢

转载自blog.csdn.net/heatsnow_/article/details/80472199