JVM运行时数据区域
Java虚拟机在运行Java程序的过程中会把它所管理的内存划分为多个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间。本文将带你理解JVM的各大数据区域以及用途。
01
程序计数器
程序计数器是线程私有的,它的主要作用是记录当前线程执行到了那一条指令。线程有可能因为时间片轮转的关系导致挂起,或者是线程上下文切换,这个时候就需要记录下一条执行的指令。
02
Java虚拟机栈
与程序计数器类似,Java虚拟机栈也是线程私有的,它与线程的生命周期相同。换句话说,线程终止Java虚拟机栈将会消失。Java虚拟机栈主要存储局部变量表、操作数栈、动态连接等。
考虑到栈,一般都是有栈深的。一个程序是递归调用而没有终止,将会导致线程请求的栈深大于虚拟机所允许的栈深,那么将会抛出StackOverflowError异常。有意思的是,每一次执行程序栈的深度都不一样。
栈除了StackOverflowError异常外,如果没有足够的内存来扩展,将会抛出OutOfMemoryError异常。
03
本地方法栈
不同于Java虚拟机栈,本地方法栈中执行的方法都是Native方法,主要是C或者C++语言写的程序。与Java虚拟机栈相似的,这个区域依然会抛出StackOverflowError和OutOfMemoryError异常。
04
Java堆
如果把JVM运行时区域分为两大块,一份是非堆,另外一份则是堆。Java堆是JVM管理内存的最大一块,也是线程共享的一块区域。在这块区域上。分配了内存用于存放几乎所有的对象实例和数组。由于这个区间分配对象空间,垃圾回收的主要地方也是该区域。
Java堆可以分为新生代和老年代,再细致一点可以分为Eden空间、FromSurvivor空间、To Survivor空间。
可以通过(-Xmx和-Xms)来控制Java堆的大小,如果没有内存来分配对象,将会抛出OutOfMemoryError。
05
方法区
方法区和Java堆一样是线程共享的,它主要存储已被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
可以通过-XX:MaxPermSize提高这个区域的大小,避免OutOfMemoryError异常。
06
运行时常量池
运行时常量池作为作为方法区的一部分,主要存储编译生成的各种字面量和符号引用。如果有废弃的常量,也会被垃圾回收器回收。
运行时常量池也会受内存大小限制,会抛出OutOfMemoryError异常。
07
直接内存
直接内存不属于JVM运行数据的一部分,是在JDK1.4以后NIO类的加入后引入一种基于通道和缓冲区的I/O方式。这样做的好处是在某些场景下,避免了应用程序空间和本地空间之间数据的复制,提高了性能。
如果这部分内存频繁使用,可能导致OutOfMemoryError异常
08
总结
Java虚拟机的运行时内存区域主要分为程序计数器、Java虚拟机栈、本地方法栈、堆和方法区。其中,程序计数器和Java虚拟机栈都是线程私有的,堆和方法区是线程共享的。当然,方法区中还有运行时常量池,主要用于存储常量。
直接内存的引用在是由于NIO类的加入,在某些场景下可以避免数据复制次数。提高性能。
点击上方蓝色字体,关注我们
15
好看你就点点我