Java8移除永久代 起因: 最近看深入理解Java虚拟机, 在实战OutOfMemoryError的运行时常量池溢出时, 我的Intellij提示如下: Java HotSpot(TM) 64-Bit 因为使用永久代来实现方法区不是个好主意, 很容易遇到内存溢出的问题. 我们通常使用PermSize和MaxPermSize设置永久代的大小, 这个大小就决定了永久代的上限, 但是我们不是总是知道应该设置为多大的, 如果使用默认值容易遇到OOM错误. 其中 “JEP 122: Remove the Permanent Generation“说的就是移除永久代. 减少OOM只是表因, 更深层的原因还是要合并HotSpot和JRockit的代码, JRockit从来没有一个叫永久代的东西, 但是运行良好, 也不需要开发运维人员设置这么一个永久代的大小.
Java 8为什么使用元空间替换永久代? 在Java 8中,Java开发团队做出了一个重要的变革:将永久代(Permanent Generation,或PermGen)移除,并引入了元空间(Metaspace)。 本文将详细探讨为什么Java 8选择使用元空间替代永久代,以及这一变化带来的好处和挑战。 二、元空间的引入 2.1 元空间的定义 元空间(Metaspace)是Java 8中引入的新的内存区域,用于存储类的元数据。与永久代不同,元空间使用本地内存(native memory)而不是堆内存。 六、结论 Java 8中引入的元空间替代永久代是JVM内存管理的一个重要改进。元空间通过使用本地内存和动态扩展机制,解决 了永久代固定大小带来的种种问题,提高了内存使用的灵活性和效率。
由于方法区主要存储类的相关信息,所以对于动态生成类的情况比较容易出现永久代的内存溢出。最典型的场景就是,在 jsp 页面比较多的情况,容易出现永久代内存溢出。 因此,可以大致验证 JDK 1.7 和 1.8 将字符串常量由永久代转移到堆中,并且 JDK 1.8 中已经不存在永久代的结论。现在我们看看元空间到底是一个什么东西? 元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。 四、总结 通过上面分析,大家应该大致了解了 JVM 的内存划分,也清楚了 JDK 8 中永久代向元空间的转换。不过大家应该都有一个疑问,就是为什么要做这个转换? 2、类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。 3、永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
由于方法区主要存储类的相关信息,所以对于动态生成类的情况比较容易出现永久代的内存溢出。最典型的场景就是,在 jsp 页面比较多的情况,容易出现永久代内存溢出。 因此,可以大致验证 JDK 1.7 和 1.8 将字符串常量由永久代转移到堆中,并且 JDK 1.8 中已经不存在永久代的结论。现在我们看看元空间到底是一个什么东西? 元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。 从输出结果,我们可以看出,这次不再出现永久代溢出,而是出现了元空间的溢出。 四、总结 通过上面分析,大家应该大致了解了 JVM 的内存划分,也清楚了 JDK 8 中永久代向元空间的转换。 2、类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。 3、永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
由于方法区主要存储类的相关信息,所以对于动态生成类的情况比较容易出现永久代的内存溢出。最典型的场景就是,在 jsp 页面比较多的情况,容易出现永久代内存溢出。 因此,可以大致验证 JDK 1.7 和 1.8 将字符串常量由永久代转移到堆中,并且 JDK 1.8 中已经不存在永久代的结论。现在我们看看元空间到底是一个什么东西? 元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。 四、总结 通过上面分析,大家应该大致了解了 JVM 的内存划分,也清楚了 JDK 8 中永久代向元空间的转换。不过大家应该都有一个疑问,就是为什么要做这个转换? 类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。 永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
摘要 在JDK8之前,类的元数据和常量都存放在一个与堆内存相邻的数据区,即永久代。但是在这种情况下有一个问题,如果类的元数据大小超过了应用的可分配内存,那么就会出现内存溢出问题。 在JDK8之后,永久代被移除,原本存储在永久代的数据将存放在一个叫做元空间的本地内存区域。 在JDK8之前的HotSpot虚拟机中,类的这些“永久的”数据存放在一个叫做永久代的区域。 永久代一段连续的内存空间,我们在JVM启动之前可以通过设置-XX:MaxPermSize的值来控制永久代的大小,32位机器默认的永久代的大小为64M,64位的机器则为85M。 辞永久代,迎元空间 随着Java8的到来,我们再也见不到永久代了。但是这并不意味着类的元数据信息也消失了。这些数据被移到了一个与堆不相连的本地内存区域,这个区域就是我们要提到的元空间。
在JDK8之前的HotSpot JVM,存放这些”永久的”的区域叫做“永久代(permanent generation)”。 永久代的垃圾收集是和老年代(old generation)捆绑在一起的,因此无论谁满了,都会触发永久代和老年代的垃圾收集。 注:从JDK7开始永久代的移除工作,贮存在永久代的一部分数据已经转移到了Java Heap或者是Native Heap。 永久代在JDK8中被完全的移除了。所以永久代的参数-XX:PermSize和-XX:MaxPermSize也被移除了。 2、类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。 3、永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
永久代的相关知识 ---- JDK1.8之后取消。 永久代是在堆内存中保存的,但不会被回收,例如:intern()方法产生的对象不会被回收。 所以如果你的操作不当,导致永久代中数据量过大,那么这个时候程序依然会抛出OOM异常。 设置永久代的内存参数 ---- No. 参数名称 描述 01 -XX:PermSize 设置永久代的初始大小 02 -XX:MaxPermSize 设置永久代的最大值 3. 范例 ---- 1. 在JDK1.8之中设置永久代会出现错误提示
再重复一遍就是对Java7及以前版本的Hotspot中方法区位于永久代中。同时,永久代和堆是相互隔离的,但它们使用的物理内存是连续的。 永久代的垃圾收集是和老年代捆绑在一起的,因此无论谁满了,都会触发永久代和老年代的垃圾收集。 但在Java7中永久代中存储的部分数据已经开始转移到Java Heap或Native Memory中了。 然后,在Java8中,时代变了,Hotspot取消了永久代。永久代真的成了永久的记忆。永久代的参数-XX:PermSize和-XX:MaxPermSize也随之失效。 元空间(Metaspace) 对于Java8,HotSpots取消了永久代,那么是不是就没有方法区了呢?当然不是,方法区只是一个规范,只不过它的实现变了。 原文链接:《面试官,Java8 JVM内存结构变了,永久代到元空间》 《面试官》系列文章: 《JVM之内存结构详解》 《面试官,不要再问我“Java GC垃圾回收机制”了》
永久代(PermGen) 上面理解了规范和实现之后,来看认识一个概念“永久代(Permanet Generation,也称PermGen)”。 再重复一遍就是对Java7及以前版本的Hotspot中方法区位于永久代中。同时,永久代和堆是相互隔离的,但它们使用的物理内存是连续的。 永久代的垃圾收集是和老年代捆绑在一起的,因此无论谁满了,都会触发永久代和老年代的垃圾收集。 但在Java7中永久代中存储的部分数据已经开始转移到Java Heap或Native Memory中了。 然后,在Java8中,时代变了,Hotspot取消了永久代。永久代真的成了永久的记忆。永久代的参数-XX:PermSize和-XX:MaxPermSize也随之失效。 元空间(Metaspace) 对于Java8,HotSpots取消了永久代,那么是不是就没有方法区了呢?当然不是,方法区只是一个规范,只不过它的实现变了。
JRockit 客户不需要配置永久层代(因为 JRockit 没有永久代),所以要移除永久代。 JRockit 是 Java 官方收购的一家号称史上运行最快的 Java 虚拟机厂商,之后 Java 官方在 JDK 8 时将 JRockit 虚拟机和 HotSpot 虚拟机进行了整合。 永久代”,所以把永久代给移除了。 2.背后的原因 上述给出了移除永久代的回答,但却没有给出背后的原因,那接下来我们就来讨论一下,为什么要移除永久代?以及为什么要有元空间? 3.方法区发展史 在 HotSpot 虚拟机中,方法区的实现经历了以下 3 个阶段: JDK 1.6 及之前:方法区使用永久代实现,静态变量存放在永久代; JDK 1.7 :“去永久代”的前置版本,还存在永久代
排查过程 登入机器,查看内存使用高的进程: top pid:15298 既然是perm区问题,查看永久代情况: jmap -permstat pid > 15298dump.permstat class_loader ASMClassLoader@0x00000007c44de0e0 4785232 N/A 5146 sun/misc/Launcher$AppClassLoader@0x00000007c021c2d8 最近发版比较少,同时这些是扩容机器,在最近的几次发版中并没有发版,所以造成类加载持续一段时间,最后造成永久代泄露。
之前已经讲过了不少有关 JVM 的内容,今天准备将之前没有细讲的部分进行补充,比如:永久代和元空间。 永久代 Java 的内存中有一块称之为方法区的部分,在 JDK8 之前, Hotspot 虚拟机中的实现方式为永久代(Permanent Generation),别的JVM都没有这个东西。 永久代是一段连续的内存空间,我们在 JVM 启动之前可以通过设置-XX:MaxPermSize的值来控制永久代的大小,32 位机器默认的永久代的大小为 64M,64 位的机器则为 85M。 永久代的垃圾回收和老年代的垃圾回收是绑定的,一旦其中一个区域被占满,这两个区都要进行垃圾回收。 元空间 元空间是 Hotspot 在 JDK8 中新加的内容,其本质和永久代类似,都是对 JVM 规范中方法区的实现。不过元空间与永久代之间最大的区别在于: 元空间并不在虚拟机中,而是使用本地内存。
永久代: 在jdk7以及jdk7之前,方法区被称为永久代(PermGen) 此时永久代是 Java 堆(Java Heap)的一部分,用于存储类信息、方法信息、常量池信息等静态数据。 在Java7时,仍然有永久代,永久代也与堆中的老年代连续,但永久代中存储的部分数据已经开始转移到Java Heap或Native Memory中了,比如: 符号引用(Symbols)转移到了Native 元空间和永久代的不同点: 存储位置不同 为什么说存储位置不同呢? 永久代在物理上是堆的一部分,和新生代、老年代的地址是连续的,而元空间属于本地内存。 这时候我们就有了新的问题,为什么要废弃永久代,而使用元空间来进行替换呢? 首先我们得知道,在原来的永久代划分中,永久代需要存放类的元数据、静态变量和常量等。 第二个原因则是移除永久代是为融合HotSpot VM与 JRockit VM而做出的努力,因为JRockit没有永久代,不需要配置永久代。
永久代(PermGen) 永久代是方法区的一种实现,它是在JVM中使用的一个术语,特别是在HotSpot虚拟机中。 在Java 8之前的版本中,HotSpot虚拟机使用永久代来存储类的元数据和其他与类相关的结构。永久代有一个固定的大小上限,可以通过JVM启动参数-XX:MaxPermSize进行设置。 元空间(Metaspace) 从Java 8开始,HotSpot虚拟机移除了永久代的概念,取而代之的是元空间。 永久代和元空间都是方法区的具体实现,但它们存在于不同的Java版本中: 「永久代」:Java 8之前的HotSpot虚拟机实现。 「元空间」:Java 8及以后版本的HotSpot虚拟机实现。 主要区别在于: 「位置」:永久代在JVM堆内存中,而元空间在本地内存中。
---- 【永久代】(JDK8之前) -XX:PermSize 设置初始永久代大小。 ---- 【元空间】(JDK8及之后) -XX:MaxMetaspaceSize 设置元空间默认初始大小,默认为20.75MB。 例如:-XX:MaxMetaspaceSize=40m 在Java8中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代。 元空间的本质和永久代类似,元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用堆外的直接内存。 因此,与永久代不同,如果不指定大小,默认情况下,虚拟机会耗尽所有的可用系统内存。 类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。永久代会位GC带来不必要的复杂度,而且回收效率偏低。
方法区和永久代的关系很像Java中接口和类的关系,类实现了接口,而永久代就是HotSpot虚拟机对虚拟机规范中方法区的一种实现方式。 对新生代进行垃圾回收叫做minor GC,对老年代进行垃圾回收叫做major GC,同时对新生代、老年代和永久代进行垃圾回收叫做full GC。 所以,理论上系统可以使用的内存有多大,元空间就有多大,所以不会出现永久代存在时的内存溢出问题。 这项改造也是有必要的,永久代的调优是很困难的,虽然可以设置永久代的大小,但是很难确定一个合适的大小,因为其中的影响因素很多,比如类数量的多少、常量数量的多少等。 永久代中的元数据的位置也会随着一次full GC发生移动,比较消耗虚拟机性能。同时,HotSpot虚拟机的每种类型的垃圾回收器都需要特殊处理永久代中的元数据。
JDK 1.8中元空间的引入 在JDK 1.8中,元空间(Metaspace)被引入作为替代永久代(PermGen,Permanent Generation)的一部分内存模型的改变。 永久代的限制 「永久代」是Java堆的一部分,用于存储类的元数据、静态变量和JVM内部用于类和方法的数据结构。它有一个固定的大小,当应用程序加载了大量的类或者大量使用反射时,永久代很容易发生溢出。 这样做的好处是元空间可以动态地根据应用程序的需求扩展大小,而不需要像永久代那样设置一个固定的大小。这种方式更加灵活,可以减少因为永久代大小不当设置导致的内存错误。 4. 性能优化 使用元空间代替永久代还有助于性能优化。因为元空间是基于本地内存的,它的扩展通常比永久代更快,且不受JVM堆大小的限制。这意味着元空间可以更快地响应类加载的需求。 5. 与HotSpot JVM的兼容性 Oracle希望通过引入元空间,简化HotSpot JVM的维护和开发,因为这样可以移除与永久代相关的代码,使得JVM的内存管理更加简洁。
/staging/src/k8s.io/client-go/util/cert/cert.go 2.修改生成的其他证书 #把24*365 换成 24*365*100 vi . [root@localhost kubernetes]# ls _output/bin/kubeadm _output/bin/kubeadm 重新安装集群 参考Kubernetes(k8s)-k8s安装 Not Before: Jan 15 03:28:50 2025 GMT Not After : Dec 22 03:28:51 2124 GMT 这样我们就实现了永久证书
在上一期《三代测序100问》中,我们深入探讨了三代长读长测序如何凭借其覆盖全长mRNA的独特优势,将转录组学研究的分辨率从基因水平提升至转录本(Isoform)水平。