http://blog.csdn.net/zhyhang/article/details/17246223
正如大家所知,JDK 8 Early Access版已经提供下载。这使开发者可以体验Java8的新特性。其中之一,是Oracle从JDK7发布以来就一直宣称的要完全移除永久代空间。例如,字符串内部池,已经在JDK7中从永久代中移除。JDK8的发布将宣告它的终结。这篇文章将会分享到目前为止对 PermGen 继任者:Metaspace的了解。我们将通过运行一个存在类元数据对象“泄漏”的程序,来对比HotSpot1.7与HotSpot1.8(b75,译者注:翻译文章时已经到b118)的运行时行为。待Java 8 正式发布之后,才会提供最终的规范,优化参数和相关文档。
元空间(Metaspace):
一种新的内存空间的诞生
JDK8 HotSpot JVM 使用本地内存来存储类元数据信息并称之为:元空间(Metaspace);这与Oracle JRockit 和IBM JVM’s很相似。这将是一个好消息:意味着不会再有java.lang.OutOfMemoryError: PermGen问题,也不再需要你进行调优及监控内存空间的使用……但请等等,这么说还为时过早。在默认情况下,这些改变是透明的,接下来我们的展示将使你知道仍然要关注类元数据内存的占用。请一定要牢记,这个新特性也不能神奇地消除类和类加载器导致的内存泄漏。你需求使用不同的方法以及遵守新的命名约定来追踪这些问题。我推荐大家阅读有关PermGen移除总结和Jon对此的评论。
总结如下:
PermGen 空间的状况
- 这部分内存空间将全部移除。
- JVM的参数:PermSize 和 MaxPermSize 会被忽略并给出警告(如果在启用时设置了这两个参数)。
Metaspace 内存分配模型
- 大部分类元数据都在本地内存中分配。
- 用于描述类元数据的“klasses”已经被移除。
Metaspace 容量
- 默认情况下,类元数据只受可用的本地内存限制(容量取决于是32位或是64位操作系统的可用虚拟内存大小)。
- 新参数(MaxMetaspaceSize)用于限制本地内存分配给类元数据的大小。如果没有指定这个参数,元空间会在运行时根据需要动态调整。
Metaspace 垃圾回收
- 对于僵死的类及类加载器的垃圾回收将在元数据使用达到“MaxMetaspaceSize”参数的设定值时进行。
- 适时地监控和调整元空间对于减小垃圾回收频率和减少延时是很有必要的。持续的元空间垃圾回收说明,可能存在类、类加载器导致的内存泄漏或是大小设置不合适。
Java 堆内存的影响
- 一些杂项数据已经移到Java堆空间中。升级到JDK8之后,会发现Java堆 空间有所增长。
Metaspace 监控
- 元空间的使用情况可以从HotSpot1.8的详细GC日志输出中得到。
- Jstat 和 JVisualVM两个工具,在我们使用b75版本进行测试时,已经更新了,但是还是能看到老的PermGen空间的出现。
前面已经从理论上充分说明,下面让我们通过“泄漏”程序进行新内存空间的观察……
PermGen vs. Metaspace 运行时比较
为了更好地理解Metaspace内存空间的运行时行为,我们建立了一个类元数据泄漏程序。可以从此处下载源代码。
将进行以下几种场景的测试:
- 使用JDK1.7运行Java程序,监控并耗尽设定的128MB大小的PermGen内存空间。
- 使用JDK1.8 (b75)运行Java程序,监控新Metaspace内存空间的动态增长和垃圾回收过程。
- 使用JDK1.8 (b75)运行Java程序,模拟耗尽通过“MaxMetaspaceSize”参数设定的128MB大小的Metaspace内存空间。
JDK 1.7 @64-bit – PermGen 耗尽测试
- Java程序中包括5万次可配置迭代过程
- Java堆大小为1024 MB
- Java的PermGen空间为128 MB(-XX:MaxPermSize=128m)
可以从上面的JVisualVM的截图看出:当加载超过3万个类之后,PermGen被耗尽。我们也能通过程序和GC的输出观察耗尽的过程。
- Class metadata leak simulator
- Author: Pierre-Hugues Charbonneau
- http://javaeesupportpatterns.blogspot.com
- ERROR: java.lang.OutOfMemoryError: PermGen space
下面我们使用HotSpot JDK 1.8 JRE来执行程序。
JDK 1.8 @64-bit – Metaspace大小动态调整测试
- Java程序中包括5万次可配置迭代过程
- Java堆大小为1024 MB
- Java的Metaspace空间:不受限制 (默认)
从上面的截图可以看到详细的GC输出日志,JVM Metaspace进行了动态扩展,本地内存的使用由20MB增长到328MB,以满足程序中不断增长的类数据内存占用需求。我们也能观察到JVM的垃圾回收事件—试图销毁僵死的类或类加载器对象。但是,由于我们程序的泄漏,JVM别无选择只能动态扩展Metaspace内存空间。程序能够运行5万次迭代,加载超过5万个类,而没有出现OOM事件。下面继续进行最后的一个测试场景:
JDK 1.8 @64-bit – Metaspace depletion
- Java程序中包括5万次可配置迭代过程
- Java堆大小为1024 MB
- Java的Metaspace空间:128MB(-XX:MaxMetaspaceSize=128m)
可以从上面的JVisualVM的截图看出:当加载超过3万个类之后,Metaspace被耗尽;与JDK1.7运行时非常相似。我们也能通过程序和GC的输出观察耗尽的过程。另一个有趣的现象是,保留的原生内存占用量是设定的最大大小两倍之多。这可能表明,如果可能的话,可微调元空间容量大小策略,来避免本地内存的浪费。
从Java程序的输出中看到如下异常。
- Class metadata leak simulator
- Author: Pierre-Hugues Charbonneau
- http://javaeesupportpatterns.blogspot.com
- ERROR: java.lang.OutOfMemoryError: Metadata space
完成!
正如预期的那样,像运行JDK1.7基线时一样,限定128 MB大小元空间时,并不能让程序完成50万次迭代。一种新的OOM错误被JVM抛出。上述OOM事件,是由于元空间内存分配失败由JVM抛出的。
#metaspace.cpp
结束语
我希望您能喜欢这篇较早的对Java8元空间的分析和实验文章。目前的观察有力地表明,适当的监控和调优是必须的,以此来避免诸如,过度的在元空间中的GC,或像我们测试场景下触发OOM的条件。后面的文章中可能包括,性能上的比较,以确定这一新特性是否有潜在的性能上的提升。
相关推荐
在Java虚拟机(JVM)中,PermGen space(永久代)是用于存储类的信息、常量、静态变量等数据的区域。在Java 8之前,PermGen space 是HotSpot JVM的一部分,并且它的大小可以通过JVM参数进行调整。 当PermGen space的...
然而,自Java 8开始, PermGen 空间已经被移除,取而代之的是Metaspace。Metaspace的出现是为了避免先前PermGen空间的限制,它不再有固定的大小上限,而是根据需要自动增长。但这并不意味着我们可以忽视内存管理,...
这种错误通常发生在永久代(PermGen space)内存不足的情况下,永久代主要用于存储类的信息、常量、静态变量以及方法信息等。本文将详细介绍这一问题的成因及解决方案。 #### 一、PermGen space简介 PermGen space...
PermGen(Permanent Generation)空间是Java虚拟机(JVM)的一部分,用于存储类定义、常量池、静态变量等永久代数据。在Java 8之前的版本中,PermGen空间是JVM内存模型的一部分。从Java 8开始,PermGen空间被Metaspace...
1. 增大PermGen空间大小:通过调整JVM启动参数,如`-XX:MaxPermSize`(Java 8之前)或`-XX:MaxMetaspaceSize`(Java 8及以后版本)来增加永久代或元空间的容量。 2. 优化类加载:减少不必要的类加载,如使用类的懒...
这个错误表明Java虚拟机(JVM)的永久代(PermGen)空间已满,无法再分配内存给新加载的类和元数据。 PermGen空间是早期JVM版本中用于存储类的元数据、字符串常量池和方法句柄等非实例化对象的地方。 当应用频繁地...
从Java 9开始,永久代已经被元空间(Metaspace)所取代。但在本例中,我们依然使用了针对永久代的配置参数,这些参数在Java 8及更早版本中非常常见。 - **-XX:PermSize=512m**:此参数指定了PermGen Space的初始...
- 从 JDK 8 开始,PermGen space 已被永久代 (metaspace) 替换。Metaspace 使用本地内存而非堆内存,因此可以更灵活地调整其大小。 #### 五、Java heap space 溢出的原因及解决方法 除了 PermGen space 溢出之外,...
6. **元空间(Metaspace)**:Java8替代了永久代(PermGen),使用元空间来存储类元数据。元空间位于 native memory 中,避免了永久代因类数量过多导致的 OutOfMemoryError。 7. **并行与并发**:JVM支持多线程执行...
Java虚拟机(JVM)在运行Java程序时,会分配不同的内存区域,包括堆空间(Heap Space)和永久代空间(PermGen Space)。这两个区域的设置不当可能导致内存溢出错误,影响程序的稳定性和效率。 1. **Java Heap Space...
在Java 8中,元空间(MetaSpace)取代了永久代(PermGen Space)。永久代是JVM中存储类元数据的区域,但在Java 8中,元数据被存储在本机内存的MetaSpace中,不再占用堆内存,从而避免了内存溢出的问题。元空间的大小...
在早期的Java版本中,方法区被划分为永久代(Permanent Generation, PermGen),用于存储类的元数据,如类名、方法信息、字段信息等。随着Java的更新,这个区域被移除并替换为MetaSpace(在Java 8及以后的版本)。 ...
3. **使用Metaspace**:升级到JDK 8及以上版本,利用Metaspace代替永久代,自动管理元数据的内存。 #### 七、总结 解决Java内存泄漏问题需要从多方面入手,包括合理设置JVM参数、优化代码逻辑、使用合适的工具进行...
8. **MetaSpace替代PermGen**:Java 8中,永久代(Permanent Generation)被MetaSpace取代,这解决了 PermGen 空间溢出的问题,并允许JVM动态调整元空间大小。 9. ** invokedynamic指令**:Java 8进一步利用了...
在现代JVM如Java 8及之后的版本中,这部分已经被元空间(Metaspace)取代。 3. **Java Stack(Java栈)**:每个线程都有自己的Java栈,用于存储方法调用的局部变量、操作数栈和方法返回地址。当栈溢出时,会抛出`...
- **PermGen**(永久代):特定于Sun HotSpot VM的一种内存区域,用于存储类元数据等信息。需要注意的是,在Java 7及以后版本中,永久代已经被Metaspace取代。 - **Native Heap (C-Heap)**:所有JVM厂商都会使用的一...
在Java虚拟机(JVM)中, permgen space(永久代)是早期版本(Java 6及更早)中用于存储类元数据的一个区域。它包含了加载类的信息,如类名、方法信息、字段信息等。然而,随着时间的推移,这种设计逐渐暴露出一些...
随着Java的发展,类元信息的存储方式从永久代转移到了使用本地内存的元空间(Metaspace)。当元空间内存放的类元信息超出限制时,会抛出OutOfMemoryError: Metaspace错误。增加-XX:MaxMetaspaceSize参数可以设置元...