【量产】JVM内存区域划分

Java Visual Machine内存区域划分

碎片化的时间,精讲局部知识。

学习起因:

虽然,JAVA相比于C、C++语言,并不需要程序员手动为生成(new)的对象分配内存和释放内存,可以把这份的工作都交由JVM来处理,从而避免因程序员忘记对已消亡的对象释放内存而导致内存泄漏和内存溢出的风险。但是,囿于软硬件配置及代码逻辑,JAVA将内存分配和释放都交由JVM自动管理也有可能出现内存泄露和溢出的状况。所以,我们必须要了解JVM是如何管理内存和释放内存的,才能应对发生的内存泄露和溢出情况。
本次仅讨论JVM内存的自动分配里的部分知识:JVM内存区域的划分,内存的释放(也就是垃圾回收)还有内存分配的细节以后再讲述。

知识储备:

操作系统中每一个进程都有一块属于自己管理的内存区域。同样,JVM也属于一个进程,JVM也有一块属于它自己管理的内存区域(设为内存区域D)。所有运行于JVM进程上的java程序都使用这一款内存区域D。我们可以称D为运行时数据区域D。

正片开始:

JVM将运行时数据区域D划分为如下所示的几个分区:

在这里插入图片描述

程序计数器

类似于操作系统进程的程序计数器,不过这里的程序计数器是指运行于JVM上的java程序中线程的程序计数器,用于放置线程当前执行字节码指令的行号,每个线程有一个独享的程序计数器。线程计数器部分是唯一一个不会存在OutOfMemoryError的区域。

Java虚拟机栈

线程隔离的,Java线程执行过程中,每一次调用一个方法,都会再java虚拟机栈中创建一个栈帧(Stack Frame),栈帧中存储了局部变量表、操作数栈、动态连接、方法出口等信息。一个方法调用完毕则将该方法的栈帧弹出。因此,方法不断的调用意味着不断的进栈。该Java虚拟机栈的存在帮助拥有它的线程记忆调用的方法经历了哪些流程,从而保证逻辑的正确性。
值得注意的是:每个虚拟机对于虚拟机栈都有一个栈深度的限制,线程中的方法调用超过了该深度会抛出StackOverFlowError异常;如果Java虚拟机容量允许扩展,当栈深度没有超过限制但是栈容量已经超过限制需要容量扩展时,又无法申请到足够的内存就会抛出OutOfMemory异常。

本地方法栈

本地方法栈于java虚拟机栈发挥的作用是相似的,区别只在于本地方法服务的是native方法调用,java虚拟机栈服务的是java方法调用;native方法也就是常说的本地方法,使用其他语言实现的方法。

Java堆

线程间共享,java堆是虚拟机管理内存中最大的一块。此内存区域的唯一目的就是存放对象实例。Java中“几乎所有”的对象实例都在这里分配内存。Java堆是垃圾收集器管理的内存区域。可以设置区域大小和是否允许扩展,并且有OutOfMemory异常。

方法区

线程间共享,用于存储已经被虚拟机加载的类型信息(依旧是类的信息)、常量、静态变量、即时编译器编译后的代码缓存等数据。这部分经常被叫做“非堆”用于区分堆内存。该区域也需要进行垃圾回收(主要是针对常量池的回收和类型卸载),只是回收的频率要小很多。并且也有OutOfMemory异常。

直接内存的概念

直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分。但是该部分也频繁被使用,而且也可能导致OutOfMemory异常出现。这一部分内存同样占据着JVM的内存区域的部分,设置虚拟机参数时不要漏掉这一部分。

参考文献:

《深入理解Java虚拟机:JVM高级特性与最佳实践(第三版)》
第二章 2.2节 运行时数据区域
作者:周志明
ISBN:9787111641247

尾巴:

以上知识点融入了自己的理解,如果有疑问或不足,欢迎评论区或私信讨论。

猜你喜欢

转载自blog.csdn.net/liangcheng0523/article/details/106300837