1. 概述
Java对于内存的管理是采用分区的方式进行管理的,不同区域的特性,存储的数据都是不同的。根据《Java虚拟机规范》的规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域
2.程序计数器
程序计数器可以看作是当前线程所执行的字节码的行号执行器,它通过标示下一条需要执行的字节码指令完成指令切换,可以说一个线程的运行就是在该计数器的不断变化下推动一步一步完成的
3.虚拟机栈
每个线程在创建的时候都会创建一个虚拟机栈,其内部保存一个个的栈帧,对应着一次次Java方法调用,是线程私有的,生命周期和线程一致
当调用一个新方法时,就构建一个栈帧压入到栈中,而一个方法执行结束,就会有一个栈帧出栈
在一条活动线程中,一个时间点上,只会有一个活动的栈帧。即当前正在执行的方法的栈帧都是有效的,这个栈帧被称为当前栈帧;如果当前方法调用了其他方法,方法返回之际,当前栈帧会传回此方法的执行结果给前一个栈帧,接着,虚拟机就是丢弃到当前栈帧,使得前一个栈帧变成当前栈帧
在《Java虚拟机规范》中,对这个内存区域规定了两类异常状况,如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverFlowError异常;如果Java虚拟机容量可以动态扩展,当栈扩展时无法申请到足够的内存将会抛出OutOfMemoryError异常
4.本地方法栈
本地方法栈(Native Method Stack)
一个Native Method 就是一个Java调用非Java代码的接口;本地方方法栈与虚拟机栈所发挥的作用是非常相似的
区别:
- 虚拟机栈执行Java方法服务
- 本地方法栈执行本地方法服务
异常机制同虚拟机栈一样
5. Java堆
Java堆是所有线程共享的一块区域,几乎所有的对象实例都在这里分配内存。
Java堆也是垃圾回收器管理的内存区域
Java虚拟机规范规定,Java堆可以是处于物理不连续的内存区域,只要逻辑是连续的即可;实现时,既可以是固定大小,也可以是可扩展的(-Xmx和-Xms),如果队中没有内存完成实例分配,并且堆无法扩展时,就会抛出OutOfMemoryError异常
6. 方法区
方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码缓存等数据
虽然Java虚拟机规范发把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫Non-Heap,目的应该是与Java堆区分开,方法区的大小和堆空间一样,可以选择固定可以扩展,方法区的大小决定了系统可以放多少个类,如果系统类太多,导致方法溢出,虚拟机同样会抛出OutOfMemoryError错误,JVM关闭后方法区即被释放
7. 运行时常量池
运行时常量池是方法区的一部分,Class文件中除了有类的版本/字段/方法/接口等描述信息外,还有一项信息是常量池表。用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放,JVM为每个已加载的类型(类或接口)都维护一个运行时常量池,在加载类和接口到虚拟机后创建。
所以运行时常量池相对于Class文件常量池的另一重要特性:具有动态性