Java 内存模型
Java不像C++由程序员直接管理内存,而是由虚拟机内存管理机制管理。
以JDK1.7为例子,内存模型如下:
内存模型
- 程序计数器 (Program Counter Register)
- Java虚拟机栈 (Java Virtual Machine Stacks)
- 本地方法栈 (Native Method Stack)
- Java堆 (Java Heap)
- 方法区 (Method Area)
- 运行时常量池 (Runtime Constant Pool)
- 直接内存 (Direct Memory)
程序计数器 (Program Counter Register)
程序计数器是一块较小的线程私有的内存空间,用了记录正在执行的虚拟机字节码指令的地址。
通过改变这个计数器的值来选取下一条字节码指令,分支、循环、跳转、异常处理、线程恢复等功能都需要依靠它来实现。
执行Native方法的时候,其值为空(Undefined)。
此内存区域是虚拟机规范唯一没有规定任何OutOfMemoryError的区域。
Java虚拟机栈 (Java Virtual Machine Stacks)
Java虚拟机栈也是线程私有的内存空间,它的生命周期和线程一样。
它是描述Java方法执行的内存模型:
每个方法在执行的同时都会创建一个栈桢(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
每个方法从调用到结束,就对应一个栈桢在虚拟机栈中入栈到出栈的过程。
本地方法栈 (Native Method Stack)
本地方法栈 (Native Method Stack)与Java虚拟机栈的作用非常相似,其区别是:
虚拟机栈为Java方法服务,本地方法栈为虚拟机用到的Native方法服务。
Java堆 (Java Heap)
Java堆是所有线程共享的内存区域,是最大的一块。
其唯一目的就是存放对象实例,也是GC管理的主要区域。
从内存回收的角度,还可以细分为: 新生代(Young Generation)和老年代(Old Generation)等。
年轻代为创建的短期对象,失效之后很快会被垃圾回收。该区又被划分为Eden和两个Survivor区域。
老年代存放的多数为存活时间较长的对象。
垃圾回收GC分为两种Minor GC、Full GC;
Minor GC发生频繁,但是仅针对年轻代。
Full GC 触发条件
- 调用System.gc()
- 老年代空间不足
- 永久代空间不足
- 空间分配担保失败
- Cocurrent mode failure
方法区 (Method Area)
方法区用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
虽然和Java堆一样是各个线程共享的内存区域,却有一个别名 Non-Heap (非堆)
在HotSpot虚拟机上“方法区”被更多人称为“永久代” (Permanent Generation),但对其它虚拟机并不存在这样的概念。
而且在JDK8里,永久代也被Metaspace所替代,位置也移到native memory里。
这样做的好处在于:简化GC的算法,full gc的时候更高效率。
运行时常量池 (Runtime Constant Pool)
运行时常量池 是方法区的一部分,用于存储编译期生成的各种字面量和符号引用,在类加载后进入方法区的运行时常量池中。
直接内存 (Direct Memory)
直接内存不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。
它属于堆外内存,受到本机内存大小、寻址空间的限制。
参考文献
- 《深入浅出Java虚拟机》