JVM学习总结:运行时数据区
JVM在执行Java程序的过程中会把它管理的内存划分为不同的区域
图1——运行时数据区
1.程序计数器
程序计数器是一块很小的内存空间,可以当作是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等功能需要这个计数器完成。
2.虚拟机栈
与程序计数器一样,虚拟机栈也是线程私有的,它的生命周期与线程相同,Java的方法在执行时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息,每个方法从调用直到执行完成,都对应着一个栈帧在虚拟机从入栈到出栈的过程。
3.本地方法栈
本地方法栈与虚拟机栈功能相似,不同的是虚拟机栈执行的是Java方法,在本地方法栈执行的是Native方法。
4.堆
堆(Heap)是JVM管理的内存中最大的一块,唯一的目的就是存放对象的实例。几乎所有的对象实例都可以在这里分配内存,随着JIT编译器的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术使得不是所有的对象实例都可以在堆中分配内存。
堆是垃圾收集器管理的主要区域,因此也叫GC堆。GC堆可以细分为新生代和老年代,新生代可以分为Eden空间,From Survivor空间和To Survivor空间。
5.方法区
用于存储已被虚拟机加载的类信息、常量、静态变量、JIT编译后的代码等数据。别名“非堆”,目的是与堆(Heap)区分开来,但是由于GC分代收集扩展至方法区,因此,方法区又被称为“永久代”。从JDK7开始永久代的移除工作,贮存在永久代的一部分数据已经转移到了Java Heap或者是Native Heap。但永久代仍然存在于JDK7,并没有完全的移除:符号引用(Symbols)转移到了native heap;字面量(interned strings)转移到了java heap;类的静态变量(class statics)转移到了java heap。随着JDK8的到来,JVM不再有PermGen。但类的元数据信息(metadata)还在,只不过不再是存储在连续的堆空间上,而是移动到叫做“Metaspace”的本地内存(Native memory)中。
6.运行时常量池
是方法区的一部分,编译好的Class文件除了有类的版本、字段、方法、接口等描述信息外,还有就是常量池,常量池包括编译生成的字面量(Interned Strings)和符号引用(Symbols)。
7.直接内存
直接内存(Direct)不是虚拟机运行时数据的一部分。JDK1.4中加入了NIO,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库分配堆外内存,通过存储在堆中的DirectByteBuffer对象作为这块内存的引用来进行操作。这样能在一些场景中提高性能,避免了在Java堆和Native中来回复制数据。