方法区和永久区/元空间之间的关系
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被移除。
元空间和永久代类似,都是对方法区的一个落地实现,他里面存储的数据比永久代纯粹很多,就是类的元数据。元空间的位置不存在于虚拟机中,而是在本地内存中。
从这里我们可以看到使用永久代的缺点:
- 永久代占用了堆的空间
- 永久代空间太大占用过多堆内存,太小存储类信息有限
- 永久代的 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:元空间)