方法区和永久区/元空间之间的关系

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了方法区和永久区/元空间之间的关系相关的知识,希望对你有一定的参考价值。

参考技术A 永久区和元空间的区别,永久区是占用jvm虚拟机的内存,而元空间则是占用本地内存,也就是虚拟机之外的内存,极大的减少OOM情况的发生。

方法区永久代元空间

文章目录

方法区、永久代、元空间

概念:

网上这么说的:

  • 方法区是 JVM 规范中定义的一块内存区域,用来存储类元数据、方法字节码、即时编译器需要的信息等

  • 永久代是 Hotspot 虚拟机对 JVM 规范的实现(1.8 之前)

  • 元空间是 Hotspot 虚拟机对 JVM 规范的另一种实现(1.8 以后),使用本地内存作为这些信息的存储空间

这能看懂???看个屁懂!!!

不懂那来解读一下:

首先方法区是逻辑上的东西,是 JVM 的规范,划重点!是一个规范,所有虚拟机必须遵守的。

永久代和元空间呢 :他们是方法区的实现,划重点!是一个实现,他俩大体上是这么区分的:

  • 永久代是JDK7及之前JVM实现方法区的方式

  • 元空间JDK8及之后JVM实现方法区的方式

下面来详细看一下他俩的区别:

区别:

永久代是jdk1.7之前对方法区的一个落地实现,存在于堆中,用于存储类的信息和字符串常量池,同样包含SE库的类和方法。在jdk1.7时将字符串常量池从永久代移动到堆中,永久代在jdk8被移除。

元空间和永久代类似,都是对方法区的一个落地实现,他里面存储的数据比永久代纯粹很多,就是类的元数据。元空间的位置不存在于虚拟机中,而是在本地内存中。

从这里我们可以看到使用永久代的缺点:

  1. 永久代占用了堆的空间
  2. 永久代空间太大占用过多堆内存,太小存储类信息有限
  3. 永久代的 GC 会触发堆的 GC

那为啥之前还用呢?

当时还是32位机,并看的不是很清楚,到现在64位机,弊端就暴露出来。

so,基于众多问题,jdk1.8起开始取代永久代存放类信息,元空间解决了永久代的问题

当然元空间也存在的着问题:

元空间是按照类加载器分配空间的,也就是说类加载器加载了一个类,元空间分配给这个类的空间其实是分配给的类加载器,不同的类加载器占用不同的空间,它们之间不共享类信息,如果程序中有大量的类加载器,而它们加载的类非常少,那么有可能会造成大量的空间浪费。

空间分隔开太久还可能会造成内存空间碎片化的问题。

这个佬写的里面还有代码的测试运行,感兴趣的可以看一下:https://blog.csdn.net/xiaojin21cen/article/details/104267301

图解堆与元空间的存储

从这张图学到三点

  • 当第一次用到某个类是,由类加载器将 class 文件的类元信息读入,并存储于元空间
  • X,Y 的类元信息是存储于元空间中,无法直接访问
  • 可以用 X.class,Y.class 间接访问类元信息,它们俩属于 java 对象,我们的代码中可以使用

单纯一个Y没人用它了,不会导致元空间的数据被清理掉

内存不够了,触发垃圾回收,那些不用的就会被回收,全清理了时,类加载器不使用了,被清理了,那么元空间内的数据被释放。

从这张图可以学到

  • 堆内存中:当一个类加载器对象,这个类加载器对象加载的所有类对象,这些类对象对应的所有实例对象都没人引用时,GC 时就会对它们占用的对内存进行释放
  • 元空间中:内存释放以类加载器为单位,当堆中类加载器内存释放时,对应的元空间中的类元信息也会释放

以上是关于方法区和永久区/元空间之间的关系的主要内容,如果未能解决你的问题,请参考以下文章

方法区永久代元空间

Java8内存模型—方法区 (old:永久代 new:元空间)

JVM 内存结构

JDK方法区元空间以及String.intern()知识要点

常用基础参数元空间MetaspaceSize讲解

JVM十大模块知识点,呕心沥血的整理,想不懂都难!