您可能已经知道,现在可以下载JDK 8 Early Access 。 这使Java开发人员可以尝试Java 8的一些新语言和运行时功能。这些功能之一是完全删除自Oracle自JDK 7发行以来就宣布的Permanent Generation(PermGen)空间。例如,自JDK 7起,它已从PermGen空间中删除。JDK8版本完成了其退役工作。 本文将分享我们到目前为止在PermGen后继者Metaspace上找到的信息。 当执行Java程序“泄漏”类元数据对象时,我们还将比较HotSpot 1.7与HotSpot 1.8(b75)的运行时行为。 Java 8正式发布后,有关Metaspace的最终规范,调整标志和文档应可用。
元空间:
新的存储空间诞生了
现在,JDK 8 HotSpot JVM使用本机内存来表示类元数据,这称为元空间。 类似于Oracle JRockit和IBM JVM的 。 好消息是,它不再意味着java.lang.OutOfMemoryError:PermGen空间问题,也不再需要调整和监视此内存空间……不是那么快。 虽然此更改默认情况下是不可见的,但接下来我们将向您显示,您仍然需要担心类元数据的内存占用。 还请记住,此新功能不能神奇地消除类和类加载器的内存泄漏。 您将需要使用其他方法并通过学习新的命名约定来跟踪这些问题。 我建议您阅读PermGen删除摘要和Jon对此主题的评论 。
综上所述:
PermGen空间状况
- 此内存空间已完全删除。
- PermSize和MaxPermSize JVM参数将被忽略,如果在启动时出现警告,则会发出警告。
元空间内存分配模型
- 现在,类元数据的大多数分配都是在本机内存之外分配的。
- 用来描述类元数据的分类器已被删除。
元空间容量
- 默认情况下,类元数据分配受可用本机内存量限制(容量将取决于您是否使用32位JVM与64位以及操作系统虚拟内存的可用性)。
- 一个新的标志(MaxMetaspaceSize)可用,允许您限制用于类元数据的本机内存量。 如果不指定此标志,则Metaspace将在运行时根据应用程序需求动态调整大小。
元空间垃圾收集
- 一旦类元数据使用量达到“ MaxMetaspaceSize”,就会触发死类和类加载器的垃圾收集。
- 为了限制此类垃圾收集的频率或延迟,显然将需要对Metaspace进行适当的监视和调整。 过多的Metaspace垃圾回收可能是类的征兆,类装入器的内存泄漏或应用程序的大小不足。
Java堆空间影响
- 一些其他数据已移至Java堆空间。 这意味着在将来的JDK 8升级之后,您可能会发现Java堆空间的增加。
元空间监控
- HotSpot 1.8详细GC日志输出中提供了元空间用法。
- 根据我们对b75的测试,此时Jstat和JVisualVM尚未更新,并且仍然存在旧的PermGen空间引用。
现在有足够的理论,让我们通过泄漏的Java程序来了解这种新的内存空间在起作用……
PermGen与Metaspace运行时比较
为了更好地理解新的Metaspace内存空间的运行时行为,我们创建了一个泄漏Java程序的类元数据。 您可以在此处下载源代码。
将测试以下方案:
- 为了监视和耗尽设置为128 MB的PermGen内存空间,请使用JDK 1.7运行Java程序。
- 使用JDK 1.8(b75)运行Java程序,以便监视新Metaspace内存空间的动态增加和垃圾回收。
- 使用JDK 1.8(b75)运行Java程序,以通过将MaxMetaspaceSize值设置为128 MB来模拟元空间的耗尽。
JDK 1.7 @ 64位– PermGen耗尽
- 具有50K配置的迭代的Java程序
- Java堆空间为1024 MB
- Java PermGen空间为128 MB(-XX:MaxPermSize = 128m)
从JVisualVM可以看到,在加载大约30K +类后,达到了PermGen耗尽。 我们还可以从程序和GC输出中看到这种消耗。
Class metadata leak simulatorAuthor: Pierre-Hugues Charbonneauhttp://javaeesupportpatterns.blogspot.comERROR: java.lang.OutOfMemoryError: PermGen space
现在,让我们使用HotSpot JDK 1.8 JRE执行该程序。
JDK 1.8 @ 64位– Metaspace动态调整大小
- 具有50K配置的迭代的Java程序
- Java堆空间为1024 MB
- Java Metaspace空间:无界(默认)
从详细的GC输出中可以看到,JVM Metaspace确实从20 MB扩展到了328 MB的保留本机内存,以适应Java程序中增加的类元数据内存占用量。 我们还可以观察到JVM试图破坏任何无效类或类加载器对象的垃圾回收事件。 由于我们的Java程序正在泄漏,因此JVM除了动态扩展Metaspace内存空间外别无选择。 该程序能够在没有OOM事件的情况下运行其50K迭代,并加载了50K +类。 让我们转到最后一个测试场景。
JDK 1.8 @ 64位–元空间耗尽
- 具有50K配置的迭代的Java程序
- Java堆空间为1024 MB
- Java元空间空间:128 MB(-XX:MaxMetaspaceSize = 128m)
从JVisualVM可以看到,在加载大约30K +类之后达到了元空间消耗; 与JDK 1.7的运行非常相似。 我们还可以从程序和GC输出中看到这一点。 另一个有趣的发现是保留的本机内存占用空间是指定的最大大小的两倍。 如果可能的话,这可能表明有些机会可以微调元空间重新调整大小的策略,以避免本机内存浪费。
现在在下面找到我们从Java程序输出中获得的Exception。
Class metadata leak simulatorAuthor: Pierre-Hugues Charbonneauhttp://javaeesupportpatterns.blogspot.comERROR: java.lang.OutOfMemoryError: Metadata space
做完了!
不出所料,像我们使用JDK 1.7进行基线运行一样,将Metaspace的上限限制为128 MB,这使我们无法完成程序的50K迭代。 JVM引发了一个新的OOM错误。 内存分配失败后,JVM从元空间引发了上述OOM事件。
#metaspace.cpp
最后的话
希望您对此早期分析和使用新的Java 8 Metaspace进行试验表示赞赏。 当前的观察结果明确表明,将需要进行适当的监视和调整,才能避免出现诸如上一次测试场景中触发的过多Metaspace GC或OOM条件之类的问题。 未来的文章可能会包括性能比较,以识别与此新功能相关的潜在性能改进。
参考: Java 8: Java EE支持模式和Java教程博客中的JCG合作伙伴 Pierre-Hugues Charbonneau 从PermGen到Metaspace 。
翻译自: https://www.javacodegeeks.com/2013/02/java-8-from-permgen-to-metaspace.html