Java虚拟机会在执行Java程序时将内存分为几个不同的管理区,这些区域各自有各自的用途,根据不同的特点,承担不同的任务以及在垃圾回收时运用不同的算法。总体分为下面几个部分:
- 程序计数器(Program Counter Register)
- JVM虚拟机栈(JVM Stacks)
- 本地方法栈(Native Method Stacks)
- 堆(Heap)
- 方法区(Method Area)
程序计数器(线程私有)——线程的行号指示器
- 作用:
- 在JVM解释.class的文件时,记录当前执行的行号
- 多线程操作时,记录程序的执行进度
- 几个注意的地方
- 程序计数器是唯一一个没有OutOfMemoryError情况的区域,也就是永远不会内存溢出
- Java多线程是通过线程轮流切换实现的。每条线程用一个独立的程序计数器来作为行号指示器,每个内核同一时间只处理一条线程中的某个指令。
- 如果执行的是native的方法,程序计数器为undefined
- 程序计数器每条线程都独立有一个,各个线程之间互不影响,独立存储,所以程序计数器是线程私有的。
JVM虚拟机栈(线程私有)——方法的局部变量
- Java方法执行过程就是虚拟机栈出栈和入栈的过程,他的生命周期与线程相同,也是线程私有的。它存储方法执行过程中的局部变量表、动态连接、操作数、方法出口等。很多人常说的堆栈中的栈就是指虚拟机栈中的局部变量表部分。
- 局部变量表空间大小在编译期已经确定,在运行期不会改变,其中Double和long占2个局部变量空间(Slot),其他的只占用1个。
- 他有2个异常:StackOverFlowError满栈(栈深度大于虚拟机允许的深度)和OutOfMemoryError内存溢出(扩展时无法申请空间)。
本地方法栈
其作用和虚拟机栈完全一样,只不过针对java中的native方法。
堆(共享区域)——对象实例
- 所有对象实例和数组都是在堆上分配的,堆内存是GC的主要区域,所以也叫GC堆(垃圾堆)。
- 垃圾回收是分代回收的,所以java堆分新生代和老年代。
方法区(共享区域)——永久代(类信息,常量,静态变量)
- 共享区域,存储JVM加载的类、常量、静态变量的数据。
- 相对于堆的新生代和老年代,方法区可以看成永久代,他存放一些不会变的数据(相对的),GC的行为在这个区很少发生。
- 他有一个运行时常量池用于存放在编译过程中产生的常量和引用。一般来说常量的内存分配在编译期就能确定,但也有运行时产生的,如String的intern()方法。