一,数据区域
java虚拟机在执行java程序的过程中会把它所管理 的内存分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在。有些区域则依赖用户线程的启动和结束而建立和销毁。
1. 程序计数器
一块较小的内存空间。可以理解为行号指示器,字节码解释器工作就是通过这个计数器的值来决定下一条执行的字节码指令,如分支,循环,跳转,异常处理,线程恢复等
由于java虚拟机的多线程是通过线程输液切换并分配处理器执行时间的方式来实现的,为了保证线程在切换的时候能恢复到正确的执行位置,每条线程都需要有一个独立 的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存
2. java 虚拟机栈
java虚拟机栈也是线程私有的。生命周期和线程相同。虚拟机栈描述 的是java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表,操作娄栈,动态链接,方法出口等。调用到执行的过程就是入栈到出栈的过程。
局部变量存放了各种数据类型(boolean,byte,char,short,int,float,long,double),对象引用(reference类型)
其中64位长度的long 和double类型会占用2个局部变量空间,其他的占一个。当进入一个方法时,在帧中分配的局部变量空间是完全确定的。在方法运行期间不会改变局部变量表的大小。
这个区域规定了两种情况:
- 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常
- 如果虚拟机栈可以动态扩展。如果扩展时无法申请到足够的内存将会抛出OutOfMemoryError异常
3. 本地方法栈
与虚拟机栈相似,区别是虚拟栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Naive方法服务。
与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常
4. java堆
是虚拟机所管理的内存中最大的一块内存。被所有线程共享,在虚拟机创建启动。目的是存放对象实例,几乎所有的对象实例都在这里分配内存。
java堆也是垃圾收集器管理的主要区域,也被称为 GC 堆,从内存回收的角度来看,由于现在收集器基本都采用分代收集算法,所以java堆还可细分为:新生代和老年代,再细致一点的有Eden空间,From Survivor空间,ToSurvivor空间等。从内存分配还可划分出多个线程私有的分配缓冲区
java堆可以处于物理上不连续的内存空间,只要逻辑上是连续的即可,
当前主流的虚拟机都是按照可扩展来实现的,如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常
5. 方法区
与java堆一样,线程共享的区域。用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。
很多人习惯把方法区称为”永久代”,两者本质上并不等价。
当方法区无法满足内存分配的需求时,将抛出OutOfMemoryError异常
6. 运行时常量池
运行时常量池是方法区的一部分。Class文件中除了有类的版本,字段,方法接口等描述信息外,还有常量池,用于存放编译期生成的各种字面量和符号引用。java虚拟机对Class文件的每一部分都严格规定,但对于运行时常量池,没有做任何细节的要求。
运行时常量池是方法区的一部分,自然也受到方法区内存的限制,当常量池无法申请到内存时会抛出OutMemoryError异常