java虚拟机 内存分配
分为以下几个运行时数据区:
程序计数器,java虚拟机栈,本地方法栈,java堆,方法区
程序计数器:
线程私有,记录正在执行的虚拟机字节码指令地址,执行本地方法则为空,是唯一一个java虚拟机内存中没有PutOfMemoryError情况
java虚拟机栈:
线程私有,生命周期也与线程相同,用于支持虚拟机进行方法调用和方法执行。对执行引擎来讲,只有栈顶的栈帧是有效的,称为当前栈帧,关联的方法为当前方法,所有字节指令都只针对当前栈帧操作。
有两种异常情况:
当线程请求的栈帧大于虚拟机所允许的深度,抛出StackOverflowError异常
虚拟机在动态扩展栈时无法申请到足够的内存空间,抛出OutOfMemoryError异常
栈帧所存放的信息:
局部变量表:存放方法参数和方法内部定义的局部变量,存放的数据的类型是编译期可知的各种基本数据类型,对象引用和returnAddress类型(指向一条字节码指定地址),所需内存空间在编译期完成分配,即在java程序被编译成class时就确定了局部变量表的容量,方法运行期间不会改变。32位一个slot,64位连续的两个slot
操作数栈:
又称操作栈,最大深度也在编译时确定。32位占一个栈帧,64两个。操作栈为各种字节码指令(加减赋值)提供支持
java虚拟机的解释执行引擎称为“基于栈的执行引擎”,栈就是指操作栈,也称为java虚拟机试基于栈的。Android基于寄存器,更快,但移植性不好
动态连接:
每个栈帧都包含一个指向运行时常量池(在方法区)的该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程的动态连接。
常量池存在大量符号引用,一部分会在类加载阶段或第一次使用时候转换为直接引用,称为静态解析,另一部分在每次运行期间转化为直接引用,称为动态连接
方法返回地址:恢复上层方法的局部变量表和操作数栈,有返回值则把它压入调用者栈帧的操作数栈中
本地方法栈:
与java虚拟机栈非常相似,虚拟机栈为虚拟机执行的java方法服务,本地方法栈为使用到的本地操作系统(Native)方法服务
java堆:
是虚拟机所管理的内存中最大的一块,是所有线程共享的一块内存区域。几乎所有的对象实例和数组都在这里分配内存,也是垃圾回收器管理的主要区域,也被称为GC堆
方法区:
所有线程共享,用于存储已经被虚拟机加载的类信息,常量,静态变量,即使编译器编译后的代码等数据,又被称为永久代。
运行常量池是方法区一部分,用于存放编译器生成的各种字面量和符号引用,和Class文件常量池(类的版本,字段,方法,接口等描述信息)比具有动态性