引言
JVM执行Java程序时会将它所管理的内存划分为不同的数据区域。各数据区域的生命周期也各不相同,有的随着JVM的启动而创建,有的根据用户的线程的启动和结束而创建和销毁。
程序计数器
程序计数器是一块较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器。字节码解释器就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。每条线程都需要一个程序计数器且各不影响,这类内存区域成为"线程私有"。此区域没有内存溢出的情况。
Java虚拟机栈
Java虚拟机栈也是线程私有的。Java虚拟机栈描述的是Java方法执行的内存模型。每个方法执行的同时都会创建一个栈帧用于存储局部变量表,操作数栈,动态链表,方法出口等信息。每一个方法的执行到结束的过程都对应着一个栈帧在Java虚拟机栈中的入栈和出栈过程。局部变量表存储了基本数据类型,对象引用,returnAddress(另一条字节码指令地址)。可内存溢出。
本地方法栈
本地方法栈和Java虚拟机栈的作用很相似。区别在于前者为虚拟机使用到的Native方法服务,后者是为虚拟机执行Java方法(字节码)服务。可内存溢出。
Java堆
Java堆是虚拟机所管理的内存中最大的一块。Java堆被所有线程所共享,JVM启动时创建。此内存区域唯一的目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。Java堆还是垃圾收集器管理的主要区域。Java堆可处于物理上不连续的内存中,只要逻辑上是连续的即可,可固定大小可扩展。可内存溢出。
方法区
方法区和Java堆一样也是被所有线程所共享,主要用于存储被虚拟机加载的类信息,常量,静态变量等。同样不需要连续的内存,可固定可扩展。而且垃圾收集行为极少出现。可内存溢出。
运行时常量池
运行时常量池是方法区的一部分。Class文件中除了类的版本,字段,接口等信息外还会有常量池(用于存放编译期生成的字面量和符号引用)。常量池会在类加载后进入方法区的运行时常量池,根据符号引用翻译出来的直接引用也会放入其中。Java语言不要求常量一定要在编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区的运行时常量池,程序运行期间也可以将常量放入池中。
直接内存
直接内存不是运行时数据区域的一部分,也不是Java虚拟机规范中定义的内存区域。它不受Java堆的影响,但既然是内存肯定受本机总内存影响。可内存溢出。