JVM方法区,永久代,常量池,MetaSpace 的区别

最近在学习 jvm 的相关知识,在学习到运行时数据区的方法区,挺懵逼的,看了很多文章,提及到方法区,像永久代,常量池,MetaSpace 的字汇都会跟着出来,而且都是众说纷纭的,于是查阅不少资料,终于把这几个概念搞懂了,下面就跟着这篇文章来学学jvm 的方法区到底是何方神圣。

方法区的介绍

所以到底啥是方法区,方法区的作用是啥呢,这里先摘抄于的《深入理解 java 虚拟机》的解释:

方法区(Method Area)与 Java 堆一样,是各个线程共享的内存区域,它用于存储
已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
虽然《Java 虚拟机规范》中把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫
作“非堆”(Non-Heap),目的是与 Java 堆区分开来。

这里首先说到,方法区是一个线程共享的内存区域,主要作用是存储虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据,看来方法区存的东西还不少,我们一个一个来

类型信息

这里类型信息指的是类的原数据信息,在Class文件经过类加载后,这其中会解析出类的结构信息,包括类的名称、父类、接口、字段、方法等。这些信息用于在运行时动态加载和解析类。

常量

说到常量,这里就得带入到常量池了,class文件中会有一个常量池表,这里面保存了编译期生成的各种字面量与符号引用,在类加载完成后,这部分内容将在类加载后存放到方法区的运行时常量池中。意味着运行时常量池是方法区的一部份,说到这里,大家肯定会问啥事字面量和符号引用,下面来介绍字面量和符号引用

字面量常量

字面量常量包含字符串、整数、浮点数、字符,举例说明:

String str = "Hello";  // "Hello" 在运行时常量池中存储
int num = 42;          // 42 在运行时常量池中存储

在上述代码中我们可以看到“Hello”和”42“就是字面量常量(注:java8及其以上的版本,拥有单独的字符串常量池,位置处于堆中,并不属于方法区,后续会详细说明)

符号引用

符号引用是啥呢,符号引用包含:

  1. 类的符号引用:类的全限定名(Fully Qualified Name)。
  2. 字段的符号引用:字段所属类的符号引用和字段的名称。
  3. 方法的符号引用:方法所属类的符号引用、方法名称和方法的参数类型(方法签名)。

举例说明:

class MyClass {
    private int value;

    public void setValue(int newValue) {
        this.value = newValue;
    }
}
// 类的全限定名:com.example.MyClass
// 符号引用:MyClass、setValue、value
// 字段的描述符:I (表示 int 类型)
// 方法的描述符:(I)V (表示参数为 int,返回类型为 void)

符号引用是一种抽象的引用,不直接指向内存中的地址,而是在运行时需要通过符号引用的解析过程将其转换为直接引用。解析符号引用的过程是为了在运行时确定符号引用所指向的具体内存地址,以便进行访问和调用。

符号引用的解析过程通常在类加载的链接阶段进行,将符号引用解析为直接引用后,就可以直接访问和操作类、字段或方法的内存地址。这样,当类被使用时,不需要每次都进行符号引用的解析,而是直接使用解析后的直接引用。

通过符号引用和直接引用的机制,Java 虚拟机能够实现动态绑定、多态性以及动态链接等特性,使得 Java 程序具有灵活性和可移植性。

永久代和MetaSpace

在上面我们已经了解到方法区和常量池,那么永久代和MetaSpace又是什么呢?其实解释这两个名词,和jvm的版本有关系了,在jdk1.8之前的版本中,方法区所在区域就是永久代,所以在java8之前我们可以说这两个表示的是同样的区域,但是在java8的时候,jvm废除了永久代,为啥要废除永久代呢,因为永久代是java堆的一部分,它的大小是固定,因此随着程序的运行,永久代也就是方法区类的元数据信息会越来越多,导致内存泄漏,引起频繁的full gc,甚至oom,影响程序的性能,所以废除了永久代,方法区的数据放在哪里呢,这里就引出了MetaSpace(元空间),引入了元空间(Metaspace)作为方法区的新实现。元空间使用本地内存(Native Memory)来存储类的元数据信息和常量池等内容,解决了永久代固定大小的限制和性能问题。元空间的大小可以根据应用程序的需要进行动态调整,同时具有更高的性能和更好的内存管理能力,在默认情况下,metaspace是不受jvm限制,只取决的真实的物理内存大小,当然
也可以通过参数指定:

  • -XX:MetaspaceSize:指定元空间的初始大小。
  • -XX:MaxMetaspaceSize:指定元空间的最大大小。

所以这里我们知道永久代和MeteSpace就是不同jvm版本对应方法区的不同的实现而己,这里其实还有个细节知识点,在上面方法区我们说到字符串常量池和静态变量,在java6及其以前字符串常量池是在运行时常量池中的,也就是在方法区中,在java7及其之后,字符串常量池被单独拆了出来,放到堆中,同样的静态变量也是在java7的版本中,由方法区转移到了堆中。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值