JVM内存模型
Java虚拟机(Java Virtual Machine = JVM)的内存空间分为五个部分,即:
1.程序计数器
2. Java虚拟机堆栈
3.本机方法堆栈
4.堆
5.方法区域。

以下是对这五个领域的深入介绍。
一、程序计数器
1. 1.什么是程序计数器?
程序计数器是一个很小的存储空间,可以看作是当前线程正在执行的字节码的行号的指示器。换句话说,程序计数器记录了当前线程当前正在执行的字节码指令的地址。
注意:但是,如果当前线程正在执行本地方法,则程序计数器此时为空。
1. 2.程序计数器的作用
程序计数器具有两个功能:
字节码解释器通过更改程序计数器顺序读取指令,从而实现代码流控制,例如顺序执行,选择,循环和异常处理。
在多线程的情况下,程序计数器用于记录当前线程的执行位置,以便在切换回该线程时,您可以知道该线程上次运行的位置。
1. 3.程序计数器的功能
这是一个很小的存储空间
线程私有。每个线程都有一个程序计数器。
是唯一不会发生OutOfMemoryError的内存区域。
生命周期是在创建线程时创建的,并程结束时终止。
二. Java虚拟机堆栈(JVM堆栈)
2. 1.什么是Java虚拟机堆栈?
Java虚拟机堆栈是描述Java方法运行过程的内存模型。
Java虚拟机堆栈为每个要运行的Java方法创建一个称为“堆栈框架”的区域。该区域用于存储该方法在其操作期间所需的一些信息。这些信息包括:
局部变量表
存储基本数据类型变量,引用类型变量和returnAddress类型变量。
操作数堆栈
动态链接
方法导出信息
等待
当一种方法将要执行时,Java虚拟机堆栈将首先在Java虚拟机堆栈中为该方法创建一个“堆栈框架”。堆栈框架包含局部变量表,操作数堆栈,动态链接和方法出口。信息等。当方法需要在操作期间创建局部变量时,该局部变量的值将存储在堆栈帧的局部变量表中。
执行此方法时,与该方法相对应的堆栈帧将从堆栈中弹出,并释放内存空间。
注意:经常说Java的内存空间分为“堆栈”和“堆”。局部变量存储在堆栈中,对象存储在堆中。
这句话并不完全正确!可以通过这种方式理解此处的“堆”,但是此处的“堆栈”仅表示Java虚拟机堆栈中局部变量表的一部分。真正的Java虚拟机堆栈由堆栈框架组成,每个堆栈框架具有:局部变量表,操作数堆栈,动态链接,方法导出信息。
2. 2. Java虚拟机堆栈的功能
执行该方法时将创建局部变量表,并创建堆栈框架。此外,局部变量表的大小是在编译时确定的,创建时仅需要分配预定大小。另外,在方法运行期间,局部变量表的大小不会改变。
Java虚拟机堆栈中发生两个异常:StackOverFlowError和OutOfMemoryError。
a)StackOverFlowError:
如果Java虚拟机堆栈的内存大小不允许动态扩展,则当线程请求堆栈的深度超过当前Java虚拟机堆栈的最大深度时,将引发StackOverFlowError异常。
b)OutOfMemoryError:
如果Java虚拟机堆栈的内存大小允许动态扩展,并且当线程请求堆栈时内存已用完,并且无法再动态扩展,则此时将抛出OutOfMemoryError异常。
Java虚拟机堆栈也是线程专用的。每个线程都有自己的Java虚拟机堆栈,该虚拟机堆栈是在创建线程时创建的,并随着线程的死而消失。
注意:StackOverFlowError与OutOfMemoryError之间有什么异同?
StackOverFlowError表示当前线程请求的堆栈超出了堆栈的预定最大深度,但是可能有很多内存空间。
OutOfMemoryError指的是以下事实:当线程申请堆栈时,发现堆栈已满,并且内存全部用完。
3.本机方法堆栈
3. 1.什么是本机方法堆栈?
由本地方法堆栈和Java虚拟机堆栈实现的功能相似,不同之处在于本地方法区域是本地方法操作的内存模型。
执行本地方法时,还将在本地方法堆栈中创建一个堆栈框架,以存储本地变量表,操作数堆栈,动态链接和本地方法的导出信息。
执行该方法后,将弹出相应的堆栈帧并释放内存空间。
它还会引发StackOverFlowError和OutOfMemoryError异常。
4.堆
4. 1.什么是堆?
堆是用于存储对象的内存空间。
几乎所有对象都存储在堆中。
4. 2.堆的特征
线程共享
整个Java虚拟机只有一个堆,并且所有线程都访问同一堆。程序计数器,Java虚拟机堆栈和本地方法堆栈都对应一个线程。
在虚拟机启动时创建
垃圾收集的主要场所。
它可以进一步细分为:新一代和老一代。
新一代可以分为:伊甸园,从幸存者到幸存者。
不同区域存储具有不同生命周期的对象。这样,可以根据不同的区域使用不同的垃圾收集算法,从而更具针对性和效率。
堆的大小可以是固定的或可扩展的,但是主流虚拟机堆的大小是可扩展的,因此当线程请求分配内存但堆已满并且内存已满且无法扩展时,它将抛出OutOfMemoryError。
5.方法区域
5. 1.什么是方法区域?
Java虚拟机规范中定义的方法区域是堆的逻辑部分。
方法区域存储虚拟机已加载的类信息,常量,静态变量,即时编译器编译的代码等。
5. 2.方法区域的特征
线程共享
方法区域是堆的逻辑部分,因此它被堆之类的线程共享。整个虚拟机中只有一个方法区域。

永久世代
方法区域中的信息通常需要存在很长时间,并且它是堆的逻辑分区。因此,使用堆划分方法,我们将方法区域称为旧方法。
内存回收效率低
方法区域中的信息通常需要存在很长时间,并且回收内存后可能只有很少的信息是无效的。
方法区域中的内存恢复的主要目标是:常量池的恢复和类型的卸载。
Java虚拟机规范对方法区域有相对宽松的要求。
就像堆一样,它允许固定大小,可扩展大小,并且没有垃圾回收。
5. 3.什么是运行时常量池?
方法区域中存储了三种类型的数据:类信息,常量,静态变量和即时编译器编译的代码。常量存储在运行时常量池中。
我们通常通过public static final在类中声明一个常量。编译该类后,将生成一个Class文件,并将该类的所有信息存储在该类文件中。
当Java虚拟机加载此类时,该类文件中的常量将存储在方法区域中的运行时常量池中。并且在操作过程中,可以将新的常量添加到常量池中。例如,String类的intern()方法可以在运行时将字符串常量添加到常量池中。
当常量池中的某些常量在运行时没有被对象引用,也没有由变量引用时,则需要垃圾回收器来回收它们。
6.直接存储
直接内存是Java虚拟机以外的内存,但是Java也可以使用它。
NIO中引入了基于通道和基于缓冲区的IO方法。它可以通过调用本地方法直接在Java虚拟机外部分配内存,然后通过存储在Java堆中的DirectByteBuffer对象直接操作内存,而无需先将外部存储器中的数据复制到堆中然后进行操作,从而提高了性能。提高数据操作效率。
直接内存的大小不受Java虚拟机的控制,但是由于它是内存,因此当内存不足时会引发OOM异常。
总结
Java虚拟机的内存模型中有两个“堆栈”,即:Java虚拟机堆栈和本地方法堆栈。
两个“堆栈”的功能是相似的,并且都是方法运行过程的内存模型。并且这两个“堆栈”的内部结构是相同的,并且都是线程专用的。
仅仅是Java虚拟机堆栈描述了Java方法运行过程的内存模型,而本地方法栈是描述了Java本机方法运行过程的内存模型。
Java虚拟机的内存模型中有两个“堆”,一个是原始堆,另一个是方法区。方法区域本质上是堆的逻辑部分。对象存储在堆中,而类信息,常量,静态变量和由即时编译器编译的代码存储在方法区域中。
堆是Java虚拟机中最大的内存区域,也是垃圾收集器的主要工作区域。
程序计数器,Java虚拟机堆栈和本地方法堆栈是线程专用的,也就是说,每个线程都有自己的程序计数器,Java虚拟机堆栈和本地方法区域。它们的生命周期与它们所属的线程相同。
堆和方法区域由线程共享。 Java虚拟机中只有一个堆和一个方法堆栈。它是在JVM启动时创建的,只有在JVM停止时才被销毁。
如果您还对Java的高并发,分布式,高性能,spring和其他技术感兴趣,则可以关注我的微信公众号(Javasuiyue)或搜索Java后端高级,这是一篇8点干的文章。每天都在计时!
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shoujiruanjian/article-370467-1.html
这个不是很懂
空军队有无数的英雄王海