一、程序计数器(Program Counter Register):
类似于PC寄存器,记录线程的执行位置,线程私有,执行JAVA方法时存储执行指令的地址。
唯一一个在JAVA虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
二、虚拟机栈(VM Stack)
线程私有,每次调用一个方法就开辟一个栈帧,执行结束后弹出。
栈的默认大小是1M。
栈帧(Stack Frame):
{
局部变量表:存放编译期可知的各种基本数据类型、对象引用(reference)和returnAddress类型。其中long 和double类型的数据会占用两个局部变量空间(Slot),其余只占用一个。Slot是可以重用的,但Slot中的变量超出了作用域,那么下一次分配Slot的时候会覆盖原来的数据。Slot对对象的引用会影响GC。
操作数栈:和局部变量区一样,操作数栈也是被组织成一个字长为单位的数组。但是操作数栈不是通过索引来访问,而是通过标准的栈操作(压栈和出栈)来访问。
}
三、本地方法栈(Native Stack):
和虚拟机栈相似,执行Native方法时使用,虚拟机规范对于本地方法栈中,方法使用的语言、使用方式和数据结构没有强制规定,最常用的HotSpot虚拟机直接将本地方法栈和虚拟机栈合二为一。
四、JAVA堆(JAVA Heap)
对于大多数应用来说JAVA Heap是JVM说管理的内存中最大的一块。JAVA堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。
JAVA Heap主要用于存放对象实例,几乎所有的对象实例都在这里分配内存。
JAVA Heap是GC的主要区域,分为
{
新生代(The NewGenerational Heap)默认4M,此区域一般为JVM内存的1/15大小
{
Eden区:绝大多数刚创建的对象会分配在Eden区,其中的大多数对象很快就会消亡,Eden区是连续的内存空间,因此在其上分配内存极快。
Survivor区:
{
Survivor区:
当Eden区满的时候执行Minor GC,并将剩余的对象添加到Survivor区。
Empty Survivor区:
当Survivor区满的时候将其中活着的对象复制到Empty Survivor区,然后清空Survivor区,紧接着现在Empty Survivor区成为Survivor区,
之前的Survivor成为Empty Survivor区,以后Eden区满了活着的对象就会放在当前Survivor区
}
}
老年代(Tenured Genaration)
{
Tenured区:
当一个对象在Survivor两个区游荡了n(可设置)个来回之后,对象进入Tenured区。除此之外,如果对象较大,年轻代空间不足,则大对象会直接分配到老年代上
}
}
五、方法区(Method Area)
跟堆一样是被各个线程共享的内存区域,用于存储被虚拟机加载的类信息、产量、静态变量。
在JVM启动时创建。
方法区的容量是可以固定大小的,也可以随着程序执行的需求动态扩展,方法区在实际内存空间中可以是不连续的。
/*****************************
//
public class Test {
public static void main(String[] args) {
Test t = new Test();
//JVM将Test类信息加载到方法区, new Test()产生的实例存在堆区,Test引用保存在栈区
}
}
******************************/
六、运行时常量池(Runtime Constant Pool)
运行时常量池实际上是方法区的一部分。在Class文件中,除了有类的版本、极端、方法、接口等描述信息之外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时产量池中。
七、直接内存(Direct Memory)
直接内存比不是虚拟机运行时数据区的一部分,也不是JAVA虚拟机规范中定义的内存区域,但是这部分内存也被频繁的使用,而且有可能导致内存溢出