JAVA虚拟机运行时数据区域
1.程序计数器
1)它可以看做是当前线程执行的字节代码的行指示器,通过改变计数器的值来决定下一步执行的代码
2)它是线程私有的,每个线程都有自己的程序计数器(JAVA中多线程是通过线程轮流切换、分配处理器的执行时间的方式实现的)
3)它的生命周期和线程的生命周期一致
3)如果执行的是JAVA方法,程序计数器记录的是正在执行的虚拟机字节码指令的地址,如果是native方法,计数器为空(Underfiend)
4)储蓄计数器内JAVA虚拟机内存区域中在<<JAVA虚拟机规范>>中规定任何OutOfMemoryError的内存区域
2.JAVA虚拟机栈
1)每个方法被执行的时候,都会创建一个栈帧,用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法从调用到执行结束的过程就对应着栈帧在虚拟机栈中入栈到出栈的过程
2)它是线程私有的
3)它的生命周期和线程的生命周期一致
4)局部变量表
存放了编译器的可知的各种JAVA虚拟机基本数据类型、对象引用(reference类型,它不等同与对象本身,可能是指向对象起始地址的引用指针或者指向对象的句柄或者其它的与此对象相关的位置)、returnAddress类型(指向一条字节码指令的地址)
这些数据类型在局部变量表中的存储空间以局部变量槽来表示
局部变量表的空间在编译器完成分配(一个方法需要在栈帧中分配多大的空间是确定的),在运行期间不会改变局部变量表的大小。这个大小指的是变量槽的数量。至于1个变量槽是占用32个比特、64个比特或者其它,看虚拟机的具体实现
5)虚拟机栈的容量可以动态扩充
6)<<JAVA虚拟机规范>>规定了两种异常。
StandOverfolwError:线程请求的栈的深度大于虚拟机栈的深度。也就是栈帧太多,入不了栈了。
OutOfMemeryError:JAVA虚拟机扩展时无法申请到足够的内存
3.本地方法栈
本地方法栈和虚拟机内存栈基本类似。区别是虚拟机内存栈执行的是JAVA方法,本地方法栈执行的是native方法。
有的虚拟机(HotSpot)把两者合二为一
4.JAVA堆
1)它的唯一目的就是存放对象实例,它是JAVA虚拟机管理的内存中最大的一块
2)它是所有线程共享的
3)所有线程共享的JAVA堆可以划分出多个线程私有的分配缓冲区
4)它在虚拟机启动时创建
5)它是垃圾回收器主要管理的内存区域
5)JAVA堆可以处于物理上不连续的内存空间,但在逻辑上是连续的
6)它的大小可以是固定的也可以是可扩展的,主流的虚拟机都是设计的可扩展的
7)但JAVA堆没有内存分配实例且堆无法扩展时,会报出OutOfMemoryError
5.方法区
1)它用于存储被虚拟机加载的类信息(类的版本、字段、方法、接口等)、常量、静态变量、即时编译器编译后的代码缓存等数据
2)它是线程共享的
3)它可以处于物理上不连续的内存空间,但在逻辑上是连续的
4)它的大小可以是固定的也可以是可扩展的,主流的虚拟机都是设计的可扩展的
5)它可以选择不实现垃圾收集。但是一般会进行回收,这个区域的回收目标主要是针对常量池的回收和类型的卸载。
6)它的内存空间无法满足分配需求且无法扩展时,会报出OutOfMemoryError
6.运行时常量池
1)它是方法区的一部分
2)常量池表用于存放编译期生成的各种字面量和符号引用,这部分内容在类加载后被放到运行时常量池中
3)<<JAVA虚拟机规范>>对class的格式有着严格的要求,但是对于常量池表却没有做细节要求。虚拟机可以按照自己的需求来实现这一块的内存区域。一般来说,除了保存class文件中描述的符号引用外,还会把由符号引用翻译过来的直接引用也保存在这里
4)它是动态的。除了编译期间产生的常量,运行期间也可以将新的常量放进去。如String
5)内存不足且无法申请到内存时会报出OutOfMemoryError