jvm内存结构

122 阅读6分钟

image.png

image.png

jvm内存结构:

class文件会被类加载器装载至JVM中,并且JVM会负责程序「运行时」的「内存管理」,而JVM的内存结构,往往指的就是JVM定义的「运行时数据区域」,

简单来说就分为了5大块:方法区、堆、程序计数器、虚拟机栈、本地方法栈

要值得注意的是:这是JVM「规范」的分区概念,到具体的实现落地,不同的厂商实现可能是有所区别的。

程序计数器:

Java是多线程的语言,我们知道假设线程数大于CPU数,就很有可能有「线程切换」现象,切换意味着「中断」和「恢复」,那自然就需要有一块区域来保存「当前线程的执行信息」

所以,程序计数器就是用于记录各个线程执行的字节码的地址(分支、循环、跳转、异常、线程恢复等都依赖于计数器)

虚拟机栈

每个线程在创建的时候都会创建一个「虚拟机栈」,每次方法调用都会创建一个「栈帧」。每个「栈帧」会包含几块内容:局部变量表、操作数栈、动态连接和返回地址,了解了「虚拟机栈」的组成后,也不难猜出它的作用了:它保存方法了局部变量、部分变量的计算并参与了方法的调用和返回。

本地方法栈

本地方法栈跟虚拟机栈的功能类似,虚拟机栈用于管理 Java 函数的调用,而本地方法栈则用于管理本地方法的调用。这里的「本地方法」指的是「非Java方法」,一般本地方法是使用C语言实现的。

方法区

前面提到了运行时数据区这个「分区」是JVM的「规范」,具体的落地实现,不同的虚拟机厂商可能是不一样的, 所以「方法区」也只是 JVM 中规范的一部分而已。

「JDK8前」用「永久代」实现了「方法区」,在JDK8中,已经用「元空间」来替代了「永久代」作为「方法区」的实现了。永久代和元空间都可以当做是实现了jvm方法区的规范

《深入理解Java虚拟机》书中对方法区(Method Area)存储内容描述如下:它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等。

image.png 这里我们重点关注掌握运行时常量池

3.运行时常量池 方法区,内部包含了运行时常量池

要弄清楚方法区的运行时常量池,需要理解清楚classFile中的常量池

  • 常量池

一个有效的字节码文件中除了包含类的版本信息、字段、方法以及接口等描述符信息外,还包含一项信息就是常量池表(Constant Pool Table),包括各种字面量和对类型、域和方法的符号引用常量池、可以看做是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量 等类型。

  • 运行时常量池

运行时常量池(Runtime Constant Pool)是方法区的一部分。

常量池表(Constant Pool Table)是Class文件的一部分,用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。

运行时常量池,在加载类和接口到虚拟机后,就会创建对应的运行时常量池。

JVM为每个已加载的类型(类或接口)都维护一个常量池。池中的数据项像数组项一样,是通过索引访问的。

运行时常量池中包含多种不同的常量,包括编译期就已经明确的数值字面量,也包括到运行期解析后才能够获得的方法或者字段引用。此时不再是常量池中的符号地址了,这里换为真实地址。

运行时常量池,相对于Class文件常量池的另一重要特征是:具备动态性。

运行时常量池类似于传统编程语言中的符号表(symboltable),但是它所包含的数据却比符号表要更加丰富一些。

当创建类或接口的运行时常量池时,如果构造运行时常量池所需的内存空间超过了方法区所能提供的最大值,则JVM会抛outofMemoryError异常。 方法区的演进细节

首先明确:只有Hotspot才有永久代。BEA JRockit、IBM J9等来说,是不存在永久代的概念的。原则上如何实现方法区属于虚拟机实现细节,不受《Java虚拟机规范》管束,并不要求统一。

Hotspot中方法区的变化:

版本内容
JDK1.6及以前有永久代,静态变量存储在永久代上
JDK1.7有永久代,但已经逐步 “去永久代”,字符串常量池,静态变量移除,保存在堆中
JDK1.8无永久代,类型信息,字段,方法,常量保存在本地内存的元空间,但字符串常量池、静态变量仍然在堆中

「堆」是线程共享的区域,几乎类的实例和数组分配的内存都来自于它。

「堆」被划分为「新生代」和「老年代」,「新生代」又被进一步划分为 Eden 和 Survivor 区,最后 Survivor 由 From Survivor 和 To Survivor 组成。将「堆内存」分开了几块区域,主要跟「内存回收」有关(垃圾回收机制)

image.png

JVM内存结构和Java内存模型的区别

没有啥直接关联。Java内存模型是跟「并发」相关的,它是为了屏蔽底层细节而提出的规范,希望在上层(Java层面上)在操作内存时在不同的平台上也有相同的效果

Jvm内存结构(又称为运行时数据区域),它描述着当我们的class文件加载至虚拟机后,各个分区的「逻辑结构」是如何的,每个分区承担着什么作用。

今日总结:JVM内存结构组成(JVM内存结构又称为「运行时数据区域」。主要有五部分组成:虚拟机栈、本地方法栈、程序计数器、方法区和堆。其中方法区和堆是线程共享的。虚拟机栈、本地方法栈以及程序计数器是线程隔离的)

image.png

image.png

清理时机:

元空间需要等到对象实例不再被使用、对象对应的class类也不再被使用、类加载器不再被使用,对应的元空间中的类原始信息才能被释放。

image.png