本文参考《深入理解Java虚拟机》。
JAVA 运行时内存区域划分为5个区域:程序计数器,java虚拟机栈,本地方法栈,堆和方法区。
1,程序计数器:线程私有,下一个要执行的字节码的地址;
2,java虚拟机栈:线程私有;每个JVM的线程在创建的时候,都会创建一个栈。一个栈包含很多栈桢。栈帧用来存储局部变量表(存放了编译器的各种基本数据类型如boolean、byte、char、short、int、float、long、double;对象引用(不同虚拟机存储的不同如指向对象起始地址的引用指针或者是代表对象的句柄);returnaddress类型)、操作栈、动态链接、方法出口等信息。
在java虚拟机规范中,对这个区域规定了两种异常状况:
a. 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。
b. 如果VM栈可以动态扩展,当扩展时无法申请到足够内存(或者在初始化新线程时没有足够内存在创建栈)则抛出OutOfMemoryError异常
3,本地方法栈:本地方法栈和java虚拟机栈的作用类似。只是java虚拟机栈为执行java方法(也就是字节码)服务,本地方法栈则为虚拟机使用到的native方法服务。同样有上述两种异常。
4,堆:线程共享;JVM有一个在所有线程内共享的堆。堆是给所有类的实例和数组分配内存的运行时数据区(new出来的东西都是存在堆上的)。 堆在虚拟机启动的时候创建,堆中储存的对象通过一个自动存储管理系统(垃圾回收器)进行回收。 对象从不明确的被分配(JVM从不指明对象的释放)。JVM加上没有(JVM不指定特定的自动存储管理系统)自动存储管理系统的特别的类型,(开发者可根据系统要求自主选择)并且这个存储管理技术可能被选择按照实现的系统需求。
java堆是垃圾收集器管理的主要区域,也被称为“GC堆”。
堆要么是固定大小,要么按计算需要扩展。如果一个大的堆变得多余或许会收缩。堆的内存不需要相邻。使用者可以设置堆内存的大小,如果堆能够动态的扩展。控制最大最小堆内存。
堆会出现以下异常:
如果内存溢出(若计算所需堆内存不足),则抛出OutOfMemoryError
5,方法区:线程共享;方法区类似于传统语言编译代码时的存储区域或类似于操作系统进程的文本段。他存储内容包括:每一个类的结构,如运行时常量池,字段和方法的数据;方法和构造器的代码,如用于类,实例和接口初始化的特殊方法。这个方法区在JVM启动的时候被创建,一般情况下JVM不会选择对方法区进行垃圾回收或者压缩,这个版本的JVM规范没有强制规定方法区的位置和管理编译后代码的策略。方法区可固定大小,或按需伸缩。方法区的内存不需要相邻。
运行时常量池(方法区的一部分):
运行时常量池是类和接口运行时的常量池表,它在字节码文件里。它包含几类常量。 在编译时期识别的数值常量,在运行区识别的方法或引用字段。运行区常量池类似于传统语言的字符表,但它比传统字符表所存储的范围更广。每一个运行区常量池从方法区分配内存。当类和接口被JVM创建时相应的常量池也被创建。
运行区常量池包括以下异常:当类和接口创建时,如果运行区常量池所需内存不足,则抛出OutOfMemoryError。