java虚拟机在执行java程序的过程中会把它所管理的内存划分为若干个区域,包含方法区域,堆,虚拟机栈,本地方法栈,程序计数器,其中方法区域和堆是所有线程共享的数据区。结构如图:
- 程序计数器:
占的空间较小,可以看作是字节码行号指示器,字节码解析器是通过改变它的值来选取下一条字节码指令, 分支,循环,跳转,异常处理,线程恢复等 ,都依赖它来完成。每一条线程都有独立的一个计数器,也可以看作是私有内存,如果执行本地方法,这个计数器则为空, 该区域是唯一的一个没有OutOfMemory情况的区域。
- Java虚拟机栈:
虚拟机栈描述的是java方法执行的内存模型,跟程序计数器一样,它也是每一个线程都会创建一个,每一个方法执行时,都会创建栈帧(用于存储局部变量,操作数,动态连接,方法出口等信息),伴随者栈帧的入栈,出栈意味着一个方法的开始到结束,虚拟机栈的局部变量表,存储基本数据类型(int 等),对象引用。如果方法的深度大于虚拟机栈,就会报StackOverFlowError ,比如递归调用方法的操作等,若是动态扩展的大小超过了限制则会报OutOfMemoryError..
- 本地方法栈:
类似于虚拟机栈,它为native方法提供服务。也会报栈溢出和内存溢出的错误,有些虚拟机则 把虚拟机栈和本地方法栈合二为一。
- Java堆:
java堆是虚拟机内存中最大的一块区域,被所有的线程共享,用于存储创建的对象的实例,在虚拟机启动时启动,GC所管理的主要区域,堆中还可以细分区域,比如新生代和老年代: Eden,From Survivor ,To Survivor等空间,这些区域的细分是为了GC方便回收, 堆可以是内存不连续的,只要逻辑上保持连续即可。Eclipse中同过配置文件-xmx,-xms来控制堆内存大小。
- 方法区:
同java堆一样也是所有线程共享的一块区域,用于存储已被虚拟机加载的类信息,常量,静态变量等,GC对此区域的收集行为很少出现,但并不代表GC不回收,该区域的GC主要目标是针对常量池的回收和类的卸载,类的卸载条件比较苛刻,低版本的虚拟机经常出现因为该区域的内存没有释放导致内存泄漏。
- 运行时常量区域:
该区域是方法区域的一部分,Class文件中除了有类的版本,方法,字段,接口等描述外,还有一项是常量池,这部分内容在类加载后进入方法区的常量池中存放。
- 直接内存:
该区域不属于虚拟机区域,但是经常被使用,比如NIO API等 直接调用native函数库来分配堆外内存。若虚拟机总内存小于系统内存,也回报OutOfMemoryError;