首先我们需要先复习一下jvm的大致内存图,如下:

哦~ ,想起来了,原来方法区属于jvm的运行时数据区,且作用就是存储类信息、方法信息、常量池信息等静态数据。

 (补充一下:运行时数据区中的红色是指方法区和堆是线程共享的,其他几个都是线程私有的)

好的,回想起来方法区的相关概念后,我们进入正题:

方法区是什么?

其实呢,我们经常说的方法区只是java虚拟机规范的一个概念,就像是一个接口;那么接口总要有人实现吧,所以永久代和元空间就起着这样的作用,它们实际上都是方法区,是方法区在不同jdk版本的实现。

永久代是什么?

在jdk7以及jdk7之前,方法区被称为永久代(PermGen)

此时永久代是 Java 堆(Java Heap)的一部分,用于存储类信息、方法信息、常量池信息等静态数据。

而 Java 堆是 JVM 中存储对象实例和数组的内存区域,也就是说,永久代是 Java 堆的一个子区域。

换句话说,永久代中存储的静态数据与堆中存储的对象实例和数组是分开的,它们有不同的生命周期和分配方式。

但是,永久代和堆的大小是相互影响的,因为它们都使用了 JVM 堆内存,因此它们的大小都受到 JVM 堆大小的限制。

对字符串常量池的一个扩展:

注:jdk7之前字符串常量池也存放在永久代中,而jdk7时,脱离了永久代,存放于堆空间中。

 永久代的分布如下:

元空间是什么?

在jdk8时,彻底移除了永久代,方法区正式改名为元空间(Metaspace);  

首先需要确认的是,它们的功能并没有改变,仍然是用于存储类信息、方法信息、常量池信息等静态数据。

它们最大的区别就是永久代存在于Java堆中,它的大小受到 Java 虚拟机本身大小的限制;而元空间则是一块本机内存区域,和 JVM 内存区域是分开的, 所以只受本机可用内存的限制。

那么既然与永久代不同,那元空间就具有一些永久代没有的优点,如下:

  • 它不会导致 OutOfMemoryError 错误,因为元空间的大小可以动态调整。

  • 元空间使用本机内存,而不是 JVM 堆内存,这可以避免堆内存的碎片化问题。

  • 元空间中的垃圾收集与堆中的垃圾收集是分离的,这可以避免应用程序在运行过程中因为进行类加载和卸载而频繁地触发 Full GC。

对字符串常量池的一个扩展:

jdk8中,字符串常量池都存放在堆中,而它最开始的老东家永久代已经摇身一变成为了元空间,并且脱离了java堆空间,存放在堆以外的本地内存中。

元空间分布如下:

以上就是我对方法区这几个概念的理解,如果有需要补充的地方,记得留言评论哦~

最后,其实这篇文章中我觉得大家最需要搞清楚的一句话就是:永久代和元空间是方法区不同jdk版本的实现,搞清楚这三个概念,不记混淆了,就是很大的收获了,大家就已经很棒了~

 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐