2.2.1程序计数器
占内存较小,可看作当前线程执行字节码的行号指示器.属于"线程私有"的内存.当执行Native方法是,次计数器值为空.唯一一个没有OutOfmemoryError情况的区域.
2.2.2java虚拟机栈
线程私有,与线程生命周期相同.描述的是java方法执行的内存模型:每个方法执行的同时都会创建一个栈帧,存储局部变量表,操作数栈,动态连接,方法出口等信息.每个方法的调用到结束,都对应一个栈帧入栈到出栈的过程.
局部变量表放了基本数据类型,对象引用,和returnAddress类型.其所需的内存空间在编译期间完成分配,运行期间不会改变.
如果线程请求的栈深度大于虚拟机所允许的深度,抛出StackOverflowError异常.可动态扩展,内存溢出抛出OutOfmemoryError异常.
2.2.3本地方法栈
与虚拟机栈类似,只不过是为Native方法服务.HotSpot虚拟机合二为一了.
2.2.4java堆
线程共享内存,虚拟机启动时创建.几乎所有对象实例在此分配.未逃逸的对象可以分配栈里.也有更细致的分法,后面会说.无法扩展时会抛出OutOfmemoryError异常.
2.2.5方法区
线程共享内存区域,用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据.名义上与堆分开,实际上用的是堆的永久代来实现,方便GC管理.但是内存更容易溢出,其他虚拟机没有.会逐渐采用Nativa Memory来实现方法区的规划.jdk1.7已经把字符串常量池移出. 方法区的回收目标主要是针对常量池的回收和类型的卸载.
2.2.6运行时常量池
方法区的一部分,class文件中除了有类的版本,字段,方法,接口等 还有一项信息是常量池,用于放编译期生成的各种字面量和符号引用,这部分内容,将在类加载后进入方法区的运行时常量池.
运行时常量池相对于class文件常量池的另外一个重要特征,是具备动态特性,java并不要求常量一定只有编译期才能产生,运行期间也可能将新的常量放入池中.String的intern()方法.
2.2.7直接内存
不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域.nio可以使用 Native函数库直接分配堆外内存,然后通过一个存储在java堆的DirectByteBuffer对象作为这块内存的引用进行操作.避免了在java堆和Native堆来回复制数据.也可能导致OutOfmemoryError异常.
2.3HotSpot虚拟机对象
2.3.1对象的创建
虚拟机遇到new命令时,会先去检查这个指令的参数能否在常量池中定位到一个类的符号引用,并检查这个类是否被加载,解析,初始化.如果没有就先执行类加载.
类加载后,会为新生对象分配内存.如果java堆的内存是规整的,使用 指针碰撞 法为对象分配内存.如果内存是不规整的,会有一个记录内存的列表,然后采用 空闲列表 法为对象分配内存. java堆内存的是否规整取决于GC是否带有压缩整理功能.