一、java内存分配
1、程序计数器/pc 寄存器:
线程私有,Java 虚拟机可以支持多条线程同时执行,每一条 Java 虚拟机线程都有自 己的 pc(program counter)寄存器。在任意时刻,一条 Java 虚拟机线程只会执行一个方法的代码,这个正在被线程执行的方法称为该线程的当前方法。如果这个方法不是 native 的,那 pc 寄存器就保存 Java 虚拟机正在执行的字节码指令的地址, 如果该方法是 native 的,那 pc 寄存器的值是 undefined。pc 寄存器的容量至少应当能保 存一个 returnAddress 类型的数据或者一个与平台相关的本地指针的值。
2、虚拟机栈:
线程私有,记录方法运行产生的临时变量。在Java虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机可以动态扩展,如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。
3、本地方法栈
类似虚拟机栈,有的虚拟机将两者合二为一,主要为native方法服务。
4、java堆/java heap
线程间共享,所有对象实例以及数组都在java heap上分配。Java 堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC 堆”(GarbageCollected Heap,幸好国内没翻译成“垃圾堆”)。如果从内存回收的角度看,由于现在收集器基本都是采用的分代收集算法,所以Java 堆中还可以细分为:新生代和老年代;再细致一点新生代可以分为Eden 空间、From Survivor 空间、To Survivor 空间等
5、方法区
存放java编译的类信息、常量、静态变量等。gc回收频率低,内存回收会对常量池和类型回收,方法区是java堆的逻辑组成部分,但是简单的虚拟机实 现可以选择在这个区域不实现垃圾收集与压缩。HotSpot 虚拟机的设计团队选择把GC 分代收集扩展至方法区,或者说使用永久代来实现方法区。但是Hotspot在jdk 1.8放弃了“永久代”(PermGen) 被metaspace替代。
6、运行时常量池
方法区的一部分。运行时常量池(runtime constant pool)是class文件中每一个类或接口的常量池表 (constant_pool table,见 4.4 节)的运行时表示形式,它包括了若干种不同的常量,从编译期可 知的数值字面量到必须在运行期解析后才能获得的方法或字段引用。运行时常量池类似于传统语言中的符号表(symbol table),不过它存储数据的范围比通常意义上的符号表要更为广泛。
运行时常量池相对于Class 文件常量池的另外一个重要特征是具备动态性,Java 语言并不要求常量一定只能在编译期产生,也就是并非预置入Class 文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String 类的intern() 方法。
以上每个内存区域当无法申请到内存时都会抛出异常OutOfMemoryError异常。