概述
你注意到了吗? JDK 8 早期可访问版本已经提供下载了,java 开发人员可以使用 java 8 提供的新的语言和运行特性来做一些实验。其中一个特性就是完全的移除永久代(Permanent Generation (PermGen)),这从 JDK 7 开始 Oracle 就开始行动了,比如:本地化的 String 从 JDK 7 开始就被移除了永久代(Permanent Generation )。JDK 8 让它最终退役了。
本文将会分享至今为至我收集的关于永久代(Permanent Generation )的替代者:元空间(Metaspace)的信息。我也会比较在执行 JAVA 程序时 HotSpot 1.7 和 HotSpot 1.8 (b75) 的运行行为。
关于元空间(Metaspace)最后的规范、调整参数和文档将在 Java 8 正式发布之后公开。
元空间(Metaspace):一个新的内存空间的诞生
与 Oracle JRockit 和 IBM JVM 类似,JDK 8.HotSpot JVM 开始使用本地化的内存存放类的元数据,这个空间叫做元空间(Metaspace)。
一 个好的消息是意味着 java.lang.OutOfMemoryError: PermGen 的空间问题将不复存在,并且不再需要调整和监控这个内存空间,虽然还没有那么快。当这个变化被默认执行的时候,我们会发现你任然需要担心类的元数据的内存占用率的问题,所以请记住这个新的特性并不会奇迹般的消除类和类加载器的内存泄漏。而是你需要使用一些不同的方式和学习新名词来追查这些问题。
我建议你阅读永久带移除的总结和 Jon 对这个问题的意见。
总结:
永久区的情况:
- 这个内存空间被完全的移除
- JVM 参数 PermSize 和 MaxPermSize 会被忽略,当前在启动时会有警告信息
元空间(Metaspace)内存分配模型
- 现在大多数的类元数据分配在本地化内存中。
- 我们用来描述类的元数据的 klasses 已经被移除。
元空间的容量
- 默认情况下,类元数据分配受到可用的本机内存容量的限制(容量依然取决于你使用 32 位 JVM 还是 64 位操作系统的虚拟内存的可用性)。
- 一个新的参数 (MaxMetaspaceSize) 可以使用。允许你来限制用于类元数据的本地内存。如果没有特别指定,元空间将会根据应用程序在运行时的需求动态设置大小。
元空间的垃圾回收
- 如果类元数据的空间占用达到参数 “MaxMetaspaceSize” 设置的值,将会触发对死亡对象和类加载器的垃圾回收。
- 为了限制垃圾回收的频率和延迟,适当的监控和调优元空间是非常有必要的。元空间过多的垃圾收集可能表示类,类加载器内存泄漏或对你的应用程序来说空间太小了。
java 堆空间的影响
- 一些各种各样的数据已经转移到 Java 堆空间。这意味着未来的 JDK8 升级后,您可能会发现 Java 堆空间的不断增加。
元空间监控
- 元空间的使用从 HotSpot 1.8 开始有详细的 GC 日志输出。
- 在我们基于 B75 测试的时候 Jstat 和 JVisualVM 还没有升级, 目前还是引用到老的永久代空间。现在有足够的理论,我们可以通过我们的 Java 程序泄漏的行为来观察我们的这个新的内存空间…
永久代和元空间运行时对照
为了更好的理解新的元空间运行时的行为特征,我们创建一个类元数据泄露的 java 程序,你可以在 这里下载源代码:
我们测试下面的场景:
- 使用 JDK 1.7 运行 java 程序,并且为了监控和耗尽永久代内存空间,将其设置为 128MB
- 使用 JDK1.8(B75)运行 java 程序,并且监控新的元空间内存的冬天增长和垃圾回收。
- 使用 JDK1.8(B75)运行 java 程序,通过设置 MaxMetaspaceSize 为 128MB 来同样耗尽元空间 .
JDK 1.7 @64-bit – PermGen depletion
- java 程序设置 50k 次的迭代
- java 的堆空间为 1024MB
- java 的永久代空间为 128MB (-XX:MaxPermSize=128m)
正如你看到的 JVisualVM 的报告,当加载 30K+ 的类的时候,永久代被耗尽。我们也可以从程序和 GC 的输出文件中发现耗尽。类元数据泄漏模拟器的作者 Pierre-Hugues Charbonneau 在博客: http://javaeesupportpatterns.blogspot.com 中描述了错误: ERROR: java.lang.OutOfMemoryError: PermGen space 。 现在我们使用 HotSpot JDK 1.8 JRE. 来运行程序。
JDK 1.8 @64-bit – Metaspace dynamic re-size
- Java 程序设置 50k 次的迭代
- Java 堆空间为 1024MB
- Java 元空间为无限(默认值)
正如你看到的详细的 GC 输出,为了满足我们的 Java 程序不断增加的类元数据的内存占用,JVM 元空间扩大从 20 MB 动态占用本机内存高达 328 MB。我们也可以观察垃圾收集,JVM 在试图摧毁任何死类或类加载器对象。自从我们的 Java 程序泄漏,JVM 不得不扩张元空间的内存空间。
该方案可以迭代 50K 次,并且没有 OOM 事件和加载 50K + 类。
接下去我们来看最后的测试场景:
JDK 1.8 @64-bit – Metaspace depletion
- Java 程序设置 50k 次的迭代
- Java 堆空间为 1024MB
- Java 元空间为 128 MB (-XX:MaxMetaspaceSize=128m)
正如你看到的 JVisualVM 的报告,当加载 30K+ 的类的时候,元空间被耗尽,和在 JDK1.7 的表现非常相近。我们也可以在程序和 GC 的输出日志中找到。另一个有趣的现象是,本机内存保留的占用空间是指定的最大大小的两倍之多。如果可能的话,为了避免本机内存浪费。这可能表明需要优化元空间扩张尺寸的策略,。
现在我们可以从 java 程序的输出日志中找到下面的异常:
view source print ?
1.
Class metadata leak simulator
2.
Author: Pierre-Hugues Charbonneau
3.
<a href=``"[http://javaeesupportpatterns.blogspot.com](http://javaeesupportpatterns.blogspot.com/)"``>[http://javaeesupportpatterns.blogspot.com<](/);/a>
4.
ERROR: java.lang.OutOfMemoryError: Metadata space
5.
Done!
正如预期的那样,设置元空间最大尺寸为 128 MB,就像我们在 JDK1.7 中一样没有让我们完成我们的 50K 迭代的计划。JVM 抛出一个新的 OOM 错误。上述 OOM 事件是由 JVM 从元空间在捕获一个一个内存分配失败后抛出。
#metaspace.cpp 结束语
我希望你能欣赏这个对新的 Java8 元空间的早期的分析和实验 。目前观测表明,为了远离类似在我们最后测试场景中出现的频繁的元空间 GC 和 OOM 的问题,适当的监控和调优是必须的。以后的文章中可能包括性能比较,以确定这一新功能相关的潜在性能改进。请随时提供任何意见。
最后
以上就是单身云朵为你收集整理的JAVA 8 :从永久区(PermGen)到元空间(Metaspace)的全部内容,希望文章能够帮你解决JAVA 8 :从永久区(PermGen)到元空间(Metaspace)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复