java 虚拟机在执行java程序的过程中,会把它所管理的内存划分为若干个不同的区域。
注:java 虚拟机所管理的内存将会包括以下几个运行时数据区域
1.程序计数器,字节码解释器工作时,就是通过改变这个计数器的值来选择下一条需要执行的字节码指令分支,循环,跳转,异常处理,线程恢复都需要来这个计数器完成。
注:线程私有的内存:每个线程都有一个程序计数器,互不影响,独立存储。
2.java虚拟机栈:
(1).栈帧:用于存储局域变量表,操作数栈,动态链接,方法出口等信息。
注:每一个方法从开始调用到执行完毕的过程,就是对应着一个栈帧在虚拟机中从入栈到出栈的过程。
(2).大家经常说的堆栈,栈就是虚拟机栈,或者说是里面的局部变量表部分。
注:局部变量表存放了(boolean.byte.int.float.char.short.long.double)的基本数据类型,对象引用类型(可能是一个指向存放对象起始地址的指针),和returnAddress类型
64位的long和double类型的数据会占两个局部空间,其余的占一个,此区域会报两种异常:
第一种:在虚拟机栈动态扩充时,无法申请到足够的内存,就会报OutOfMerryError异常
第二种:线程请求的栈深度大于虚拟机所允许的深度,会报StackOverFlowError异常
(3).本地方法栈(与虚拟机类型相似)
区别:虚拟机栈为java虚拟机执行java 方法服务,本地方法栈为虚拟机使用到的native方法服务
相同点:都是抛出以上两种类型的异常
注:有些虚拟机将二者合二为一,如:SunHotSpot
(4).java堆
java对在虚拟机启动时创建,被所有的线程所共享,可以处在物理上不连续的内存空间中,只要逻辑上连续即可
作用:第一,存放对象实例,几乎上所有的对象都要在堆上分配内存空间,但是随着逃逸分析和标量替换的技术日益成熟,现在也有很多实现了栈上
分配的现象,如果对中没有完成为对象分配内存空间,并且堆也无法再扩展时,就会抛出OutOfMerryError异常
第二,GC堆,是垃圾收集器管理的主要领域
(5)方法区:
被各个线程共享,用于存储被虚拟机加载过的类信息,常量,静态变量,即时编译器编译后的代码等数据,当方法区无法满足内存分配的需求时,将抛出OutOfMerryError异常。
(6)直接内存:
它并不是虚拟机运行时数据区的一部分,也不是java虚拟机规范定义的内存区域,但是这部分内存也被频繁的使用,而且也可能导致OutOfMerryError一成的出现
注:基于通道与缓存区的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在java堆中的DirctByteBuffer对象作为这块内存的引用进行操作,因为避免了在java堆和Native堆中来回复制数据,本机直接内存大小不会受java堆限制。
(7)运行时常量池:
运行时常量池是方法区的一部分,Class文件中除了有类的版本,字段,方法,接口等描述信息外,还有一项是常量池,用于存放编译器生成的字面量和符号引用,这部分内容将在
类加载后进入方法区的运行时常量池进行存放。
java虚拟机对.Class文件每一个部分的格式都有严格的规定,每一个字节用于存储那种数据,都必须符合规范上的要求才能够被虚拟机认可,装载和执行,一般来说,除了保存.Class文件中描述的符号引用外,还会把翻译出的直接引用也存在在运行时常量池中。受方法区内存限制,当内存无法再扩展时,也会报OutOfMerryError异常
以上是笔者的读书笔记总结,主要介绍了运行时数据区域的几个大的模块,希望能够对读者有用。