Java运行时数据区域

225 阅读3分钟

程序计数器

​ 程序计数器是一块小的内存空间,可看作做当前线程执行的字节码的行号指示器.

​ 因为多线程的情况下,线程切换,为了能恢复到线程的正确执行位置,每个线程独立拥有一个线程计数器,这类内存称为"线程私有内存"

​ 如果线程执行的是一个java方法,计数器指向正在执行的字节码的指令的地址,若执行的是本地方法计数器的值为空(undeifined)

Java虚拟机栈

​ Java虚拟机栈是线程私有的,描述了Java方法执行的线程内存模型:当一个方法被执行时,Java虚拟机会同步创建一个栈帧用于存储局部表量表,操作数栈,动态链接,方法出口等信息.

​ 局部变量表中存放这基本数据类型,对象引用,returnAddress类型

​ 这些数据类型在局部变量表中以局部变量槽(Slot)来表示

​ 如果线程请求的栈深度大于虚拟机所允许的深度,会发生StackOverflowError异常,若栈深度动态扩大,当无法申请到足够的内存时会抛出OutOfMemoryError异常.(HotSpot不可以动态扩展).

本地方法栈

​ 与Java虚拟栈相似,Java虚拟机栈为虚拟机执行java方法,本地方法栈为虚拟机执行本地方法,在栈深度溢出会发生StackOverflowError异常,若栈深度动态扩大,当无法申请到足够的内存时会抛出OutOfMemoryError异常.

Java堆

​ Java堆时虚拟机管理内存最大的一块,被所有线程共享,唯一目的是存放对象实例,几乎所有对象实例都存在在Java堆中.Java堆是被垃圾收集器管理的地区,也被叫做GC堆,大部分垃圾回收器都是基于分代理论来讲的,新生代,老年代,永久代,Eden,Surivivor.....

​ 从内存分配的角度来看,所有线程共享的堆中可以细分出线程私有的分配缓冲区,用于提升分配对象的效率,更好的分配和回收内存.Java堆可以处在物理上不连续的空间,但在逻辑上是连续存在的,对于大对象(如数组),大部分虚拟机处于简单实现,存储效率,可能会要求连续的内存空间.

​ Java堆既可以是固定的,又可以是可扩展的,对象实例尚未分配,而堆无法扩展时,会发生OutOfMemoryError异常.

方法区

​ 方法区所有线程共享的空间,主要存储静态变量,常量,类型信息,即时编译器的代码缓存等信息.方法区和永久代并不是等价的,HotSpot设计团队使用永久代的实现扩展到方法区,以节省编写专门内存管理代码的工作,这样的设计容易存在内存溢出的问题,JDK7,将字符串常量池和静态变量等移除,JDK8中完全废弃永久代概念,使用本地内存实现的元空间来存储剩余的信息(主要是类型信息).

运行时常量池

​ 运行时常量池时方法区的一部分主要存放编译期生成的各种字面量和字符引用,具备动态性,会发生OutOfMmoryError异常.