因为使用永久代来实现方法区不是个好主意, 很容易遇到内存溢出的问题. 我们通常使用PermSize和MaxPermSize设置永久代的大小, 这个大小就决定了永久代的上限, 但是我们不是总是知道应该设置为多大的, 如果使用默认值容易遇到OOM错误. 其中 “JEP 122: Remove the Permanent Generation“说的就是移除永久代. 文中说实现目标: 类的元数据, 字符串池, 类的静态变量将会从永久代移除, 放入Java heap或者native memory. 减少OOM只是表因, 更深层的原因还是要合并HotSpot和JRockit的代码, JRockit从来没有一个叫永久代的东西, 但是运行良好, 也不需要开发运维人员设置这么一个永久代的大小.
在JDK8之后,永久代被移除,原本存储在永久代的数据将存放在一个叫做元空间的本地内存区域。 在JDK8之前的HotSpot虚拟机中,类的这些“永久的”数据存放在一个叫做永久代的区域。 永久代一段连续的内存空间,我们在JVM启动之前可以通过设置-XX:MaxPermSize的值来控制永久代的大小,32位机器默认的永久代的大小为64M,64位的机器则为85M。 辞永久代,迎元空间 随着Java8的到来,我们再也见不到永久代了。但是这并不意味着类的元数据信息也消失了。这些数据被移到了一个与堆不相连的本地内存区域,这个区域就是我们要提到的元空间。 这项改动是很有必要的,因为对永久代进行调优是很困难的。永久代中的元数据可能会随着每一次Full GC发生而进行移动。
永久代的垃圾收集是和老年代(old generation)捆绑在一起的,因此无论谁满了,都会触发永久代和老年代的垃圾收集。 注:从JDK7开始永久代的移除工作,贮存在永久代的一部分数据已经转移到了Java Heap或者是Native Heap。 永久代在JDK8中被完全的移除了。所以永久代的参数-XX:PermSize和-XX:MaxPermSize也被移除了。 因此,可以大致验证 JDK 1.7 和 1.8 将字符串常量由永久代转移到堆中,并且 JDK 1.8 中已经不存在永久代的结论。 2、类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。 3、永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
永久代的相关知识 ---- JDK1.8之后取消。 永久代是在堆内存中保存的,但不会被回收,例如:intern()方法产生的对象不会被回收。 所以如果你的操作不当,导致永久代中数据量过大,那么这个时候程序依然会抛出OOM异常。 设置永久代的内存参数 ---- No. 参数名称 描述 01 -XX:PermSize 设置永久代的初始大小 02 -XX:MaxPermSize 设置永久代的最大值 3. 范例 ---- 1. 在JDK1.8之中设置永久代会出现错误提示
但从《Java 虚拟机规范》的层面来说,并没有所谓的“永久代”和“元空间”等区域。 JRockit 客户不需要配置永久层代(因为 JRockit 没有永久代),所以要移除永久代。 永久代”,所以把永久代给移除了。 2.背后的原因 上述给出了移除永久代的回答,但却没有给出背后的原因,那接下来我们就来讨论一下,为什么要移除永久代?以及为什么要有元空间? 3.方法区发展史 在 HotSpot 虚拟机中,方法区的实现经历了以下 3 个阶段: JDK 1.6 及之前:方法区使用永久代实现,静态变量存放在永久代; JDK 1.7 :“去永久代”的前置版本,还存在永久代
排查过程 登入机器,查看内存使用高的进程: top pid:15298 既然是perm区问题,查看永久代情况: jmap -permstat pid > 15298dump.permstat class_loader 最近发版比较少,同时这些是扩容机器,在最近的几次发版中并没有发版,所以造成类加载持续一段时间,最后造成永久代泄露。
之前已经讲过了不少有关 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没有永久代,不需要配置永久代。
Java 8为什么使用元空间替换永久代? 一、永久代的概念与问题 1.1 永久代的定义 永久代是JVM内存结构中的一个部分,专门用于存储Java类的元数据。元数据包括类的名称、方法、字段、常量池、方法字节码等。 1.2 永久代的缺陷 永久代的存在带来了一些问题,这些问题在大型Java应用程序中尤为明显: 固定大小的内存区域:永久代是一个固定大小的内存区域,必须在JVM启动时通过参数-XX:PermSize和- 垃圾回收的复杂性:永久代的垃圾回收机制较为复杂,尤其是在类卸载时,需要扫描整个永久代以标记无用的类元数据。这种操作可能导致垃圾回收暂停时间增加,影响应用程序的性能。 永久代的使用限制:由于永久代的大小是固定的,在一些动态生成类的场景(如大量使用反射、动态代理、JSP编译等)中,永久代可能会迅速耗尽,导致内存问题。
永久代(PermGen) 永久代是方法区的一种实现,它是在JVM中使用的一个术语,特别是在HotSpot虚拟机中。 在Java 8之前的版本中,HotSpot虚拟机使用永久代来存储类的元数据和其他与类相关的结构。永久代有一个固定的大小上限,可以通过JVM启动参数-XX:MaxPermSize进行设置。 一旦永久代的空间不足,就会抛出OutOfMemoryError: PermGen space错误。 永久代和元空间都是方法区的具体实现,但它们存在于不同的Java版本中: 「永久代」:Java 8之前的HotSpot虚拟机实现。 主要区别在于: 「位置」:永久代在JVM堆内存中,而元空间在本地内存中。 「大小限制」:永久代有固定的大小限制,元空间的大小受本地内存限制。
由于方法区主要存储类的相关信息,所以对于动态生成类的情况比较容易出现永久代的内存溢出。最典型的场景就是,在 jsp 页面比较多的情况,容易出现永久代内存溢出。 三、Metaspace(元空间) 其实,移除永久代的工作从JDK1.7就开始了。JDK1.7中,存储在永久代的部分数据就已经转移到了Java Heap或者是 Native Heap。 因此,可以大致验证 JDK 1.7 和 1.8 将字符串常量由永久代转移到堆中,并且 JDK 1.8 中已经不存在永久代的结论。现在我们看看元空间到底是一个什么东西? 元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。 2、类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。 3、永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
方法区和永久代的关系很像Java中接口和类的关系,类实现了接口,而永久代就是HotSpot虚拟机对虚拟机规范中方法区的一种实现方式。 对新生代进行垃圾回收叫做minor GC,对老年代进行垃圾回收叫做major GC,同时对新生代、老年代和永久代进行垃圾回收叫做full GC。 所以,理论上系统可以使用的内存有多大,元空间就有多大,所以不会出现永久代存在时的内存溢出问题。 这项改造也是有必要的,永久代的调优是很困难的,虽然可以设置永久代的大小,但是很难确定一个合适的大小,因为其中的影响因素很多,比如类数量的多少、常量数量的多少等。 永久代中的元数据的位置也会随着一次full GC发生移动,比较消耗虚拟机性能。同时,HotSpot虚拟机的每种类型的垃圾回收器都需要特殊处理永久代中的元数据。
---- 【永久代】(JDK8之前) -XX:PermSize 设置初始永久代大小。 元空间的本质和永久代类似,元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用堆外的直接内存。 因此,与永久代不同,如果不指定大小,默认情况下,虚拟机会耗尽所有的可用系统内存。 因为通常使用PermSize和MaxPermSize设置永久代的大小就决定了永久代的上限,但是不是总能知道应该设置为多大合适, 如果使用默认值很容易遇到OOM错误。 更深层的原因还是要合并HotSpot和JRockit的代码,JRockit从来没有所谓的永久代,也不需要开发运维人员设置永久代的大小,但是运行良好。 类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。永久代会位GC带来不必要的复杂度,而且回收效率偏低。
由于方法区主要存储类的相关信息,所以对于动态生成类的情况比较容易出现永久代的内存溢出。最典型的场景就是,在 jsp 页面比较多的情况,容易出现永久代内存溢出。 三、Metaspace(元空间) 其实,移除永久代的工作从JDK1.7就开始了。JDK1.7中,存储在永久代的部分数据就已经转移到了Java Heap或者是 Native Heap。 因此,可以大致验证 JDK 1.7 和 1.8 将字符串常量由永久代转移到堆中,并且 JDK 1.8 中已经不存在永久代的结论。现在我们看看元空间到底是一个什么东西? 元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。 2、类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。 3、永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
JDK 1.8中元空间的引入 在JDK 1.8中,元空间(Metaspace)被引入作为替代永久代(PermGen,Permanent Generation)的一部分内存模型的改变。 永久代的限制 「永久代」是Java堆的一部分,用于存储类的元数据、静态变量和JVM内部用于类和方法的数据结构。它有一个固定的大小,当应用程序加载了大量的类或者大量使用反射时,永久代很容易发生溢出。 这样做的好处是元空间可以动态地根据应用程序的需求扩展大小,而不需要像永久代那样设置一个固定的大小。这种方式更加灵活,可以减少因为永久代大小不当设置导致的内存错误。 4. 性能优化 使用元空间代替永久代还有助于性能优化。因为元空间是基于本地内存的,它的扩展通常比永久代更快,且不受JVM堆大小的限制。这意味着元空间可以更快地响应类加载的需求。 5. 与HotSpot JVM的兼容性 Oracle希望通过引入元空间,简化HotSpot JVM的维护和开发,因为这样可以移除与永久代相关的代码,使得JVM的内存管理更加简洁。
由于方法区主要存储类的相关信息,所以对于动态生成类的情况比较容易出现永久代的内存溢出。最典型的场景就是,在 jsp 页面比较多的情况,容易出现永久代内存溢出。 三、Metaspace(元空间) 其实,移除永久代的工作从JDK1.7就开始了。JDK1.7中,存储在永久代的部分数据就已经转移到了Java Heap或者是 Native Heap。 因此,可以大致验证 JDK 1.7 和 1.8 将字符串常量由永久代转移到堆中,并且 JDK 1.8 中已经不存在永久代的结论。现在我们看看元空间到底是一个什么东西? 元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。 类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。 永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
永久代(PermGen) 上面理解了规范和实现之后,来看认识一个概念“永久代(Permanet Generation,也称PermGen)”。 对于习惯了在HotSpot虚拟机上开发、部署的程序员来说,很多都愿意将方法区称作永久代。 本质上来讲两者并不等价,仅因为Hotspot将GC分代扩展至方法区,或者说使用永久代来实现方法区。 再重复一遍就是对Java7及以前版本的Hotspot中方法区位于永久代中。同时,永久代和堆是相互隔离的,但它们使用的物理内存是连续的。 永久代的垃圾收集是和老年代捆绑在一起的,因此无论谁满了,都会触发永久代和老年代的垃圾收集。 但在Java7中永久代中存储的部分数据已经开始转移到Java Heap或Native Memory中了。 然后,在Java8中,时代变了,Hotspot取消了永久代。永久代真的成了永久的记忆。永久代的参数-XX:PermSize和-XX:MaxPermSize也随之失效。
永久代(PermGen) 上面理解了规范和实现之后,来看认识一个概念“永久代(Permanet Generation,也称PermGen)”。 对于习惯了在HotSpot虚拟机上开发、部署的程序员来说,很多都愿意将方法区称作永久代。 本质上来讲两者并不等价,仅因为Hotspot将GC分代扩展至方法区,或者说使用永久代来实现方法区。 再重复一遍就是对Java7及以前版本的Hotspot中方法区位于永久代中。同时,永久代和堆是相互隔离的,但它们使用的物理内存是连续的。 永久代的垃圾收集是和老年代捆绑在一起的,因此无论谁满了,都会触发永久代和老年代的垃圾收集。 但在Java7中永久代中存储的部分数据已经开始转移到Java Heap或Native Memory中了。 然后,在Java8中,时代变了,Hotspot取消了永久代。永久代真的成了永久的记忆。永久代的参数-XX:PermSize和-XX:MaxPermSize也随之失效。
GC分代收集扩展至方法区,或者说使用永久代来实现方法区而已。 相对而言,垃圾收集行为在这个区域是比较少出现的,但并非数据进入了方法区就如永久代的名字一样“永久”存在了。 在其他JVM上不存在永久代。 1.2 JDK8永久代的废弃 JDK8 永久代变化如下图: ? 即:移除永久代是为融合HotSpot JVM与 JRockit VM而做出的努力,因为JRockit没有永久代,不需要配置永久代。 元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。,理论上取决于32位/64位系统可虚拟的内存大小。
最近很多同学反馈pycharm2018.3版本无法使用补丁激活或闪退问题,今天给大家带来新的激活补丁;原来使用激活码激活的同学也可以换成补丁激活了,已激活过的同学请忽略~