众所周知java8的新特性之一是完全删除了永久生成(PermGen)空间,自jdk7发布以来,Oracle就已经宣布了这一点。例如,自jdk7以来,内部字符串已经从PermGen空间中删除。jdk8版本完成了它的退役。本文将与大家分享到目前为止我们在PermGen继任者:Metaspace
上发现的信息。我们还将比较hotspots1.7和hotspots1.8(b75)在执行Java程序“泄漏”类元数据对象时的运行时行为。一旦java8正式发布,围绕Metaspace
的最终规范、调优标志和文档应该可以使用。
元空间Metaspace
一个新的记忆空间诞生了
jdk8热点JVM现在使用本机内存来表示类元数据,称为Metaspace
;类似于oraclejrockit
和IBMJVM java.lang.OutOfMemoryError:PermGen
空间问题,无需再调整和监视此内存空间…不要太快。虽然这个更改在默认情况下是不可见的,但是接下来我们将向您展示您仍然需要担心类元数据内存占用。请记住,这个新特性并不能神奇地消除类和类加载器内存泄漏。您将需要使用不同的方法并通过学习新的命名约定来跟踪这些问题。
总而言之:
PermGen空间情况
此内存空间已完全删除。
PermSize
和MaxPermSize JVM
参数将被忽略,如果在启动时出现,则会发出警告。
元空间内存分配模型
类元数据的大多数分配现在都是从本机内存中分配的。
用于描述类元数据的klasse已被删除。
元空间容量
默认情况下,类元数据分配受可用本机内存量的限制(容量当然取决于是否使用32位JVM而不是64位以及操作系统虚拟内存可用性)。
有一个新的标志可用(MaxMetaspaceSize
),允许您限制用于类元数据的本机内存量。如果不指定此标志,元空间将根据运行时的应用程序需求动态调整大小。
元空间垃圾回收
一旦类元数据使用量达到“MaxMetaspaceSize
”,就会触发对死类和类加载器的垃圾回收。
显然需要对元空间进行适当的监视和调优,以限制此类垃圾收集的频率或延迟。过多的元空间垃圾收集可能是类、类加载器内存泄漏或应用程序大小不足的症状。
Java堆空间影响
一些杂项数据已移动到Java堆空间。这意味着您可能会在未来的jdk8升级后观察到Java堆空间的增加。
元空间监测
Metaspace
用法可从HotSpot 1.8详细GC日志输出中获得。
根据我们对b75的测试,Jstat
和JVisualVM
还没有更新,旧的PermGen空间引用仍然存在。
理论足够了,让我们看看这个新的内存空间是如何通过我们泄漏的Java程序运行的…
更多细节可以参考这一篇介绍:http://javakk.com/417.html
PermGen与Metaspace运行时比较
为了更好地理解新元空间内存空间的运行时行为,我们创建了一个类元数据泄漏Java程序。你可以在这里下载源代码。
将测试以下场景:
- 使用jdk1.7运行Java程序,以监视并耗尽设置为128mb的PermGen内存空间。
- 使用jdk1.8(b75)运行Java程序,以监视新
Metaspace
内存空间的动态增加和垃圾收集。 - 使用jdk1.8(b75)运行Java程序,通过将
MaxMetaspaceSize
值设置为128mb来模拟元空间的消耗
JDK 1.7@64位-永久代消耗
- 具有50K配置迭代的Java程序
- 1024 MB的Java堆空间
- Java PermGen空间为128 MB(
-XX:MaxPermSize=128m
)
正如您在JVisualVM中看到的,PermGen耗尽是在加载了大约30K+个类之后达到的。我们也可以从程序和GC输出中看到这种消耗。
Class metadata leak simulator
Author: Pierre-Hugues Charbonneau
http://javaeesupportpatterns.blogspot.com
ERROR: java.lang.OutOfMemoryError: PermGen space
现在让我们使用hotspotsjdk1.8jre执行该程序。
JDK 1.8@64位–元空间动态调整大小
- 具有50K配置迭代的Java程序
- 1024 MB的Java堆空间
- Java元空间:无边界(默认)
从详细的GC输出中可以看到,JVM元空间确实从20mb动态扩展到328mb的保留本机内存,以满足Java程序增加的类元数据内存占用。我们还可以观察到JVM试图销毁任何死类或类加载器对象时的垃圾收集事件。由于我们的Java程序正在泄漏,JVM别无选择,只能动态扩展元空间内存空间。该程序能够在没有OOM事件的情况下运行其50K次迭代,并加载了50K+个类。让我们转到最后一个测试场景。
JDK 1.8@64位-元空间耗尽
- 具有50K配置迭代的Java程序
- 1024 MB的Java堆空间
- Java元空间:128 MB(
-XX:MaxMetaspaceSize=128m
)
正如您在JVisualVM中看到的,元空间耗尽是在加载了大约30K+个类之后达到的;这与jdk1.7的运行非常相似。我们也可以从程序和GC输出中看到这一点。另一个有趣的观察是,保留的本机内存占用是指定的最大大小的两倍。这可能表明有机会微调Metaspace resize
策略(如果可能),以避免本机内存浪费。
现在在下面找到我们从Java程序输出中得到的异常。
Class metadata leak simulator
Author: Pierre-Hugues Charbonneau
http://javaeesupportpatterns.blogspot.com
ERROR: java.lang.OutOfMemoryError: Metadata space
正如预期的那样,将元空间限制在128MB,就像我们在JDK1.7的基线运行中所做的那样,不允许我们完成程序的50K迭代。JVM抛出了一个新的OOM错误。上面的OOM事件是JVM在内存分配失败后从元空间抛出的
当前的观察结果明确表明,为了避免诸如上一个测试场景触发的过多的元空间GC或OOM条件等问题,需要进行适当的监控和调优。以后的文章可能会包括性能比较,以确定与此新特性相关的潜在性能改进。
文章来源:http://javakk.com/421.html
也欢迎大家关注我的公众号【Java老K】获取更多干货