,,Java8新特性之再见Permgen_动力节点Java学院整理

,,Java8新特性之再见Permgen_动力节点Java学院整理

本文主要介绍了Java8的新特性告别Permgen的知识,很不错,有参考价值。有需要的请参考。

很多开发者都在自己的系统中看到过“Java . lang . out memory error:perm gen space”的问题。这通常是由与类加载器和新类加载器的创建相关的内存泄漏引起的,这通常发生在代码热部署中。与官方产品相比,这个问题在开发机上出现的频率更高,产品中最常见的“问题”就是默认值太低。常见的解决方案是将其设置为256MB或更高。

PermGen space简单介绍

permagen space的全称是Permanent Generation space,是指内存的永久存储区域。先说为什么内存增益:这部分是用来存储类和元的信息的。类在加载时被放入永久空间区域,这不同于存储实例的堆区域。因此,如果您的应用程序将加载许多类,可能会出现永久空间错误。当web服务器预编译JSP时,这种错误很常见。

JVM有很多种,Oralce-Sun Hotspot,Oralce JRockit,IBM J9,淘宝JVM(淘宝好!)等等。当然武林盟主是Hotspot,这是毋庸置疑的。需要注意的是,PermGen空间只在Oracle-Sun Hotspot中可用,而JRockit和J9没有这个区域。

元空间(MetaSpace)一种新的内存空间诞生

JDK8 HotSpot JVM会移除持久化区域,使用本地内存存储类元数据信息,称为:metaspace这类似于Oracle JRockit和IBM JVM的,如下图所示。

这意味着不会再有Java了。内存不足错误:permgen问题,您将不再需要调优和监控内存空间的使用.但是请等等,现在这么说还为时过早。默认情况下,这些更改是透明的。接下来,我们的演示将让您知道,您仍然需要注意类元数据的内存占用。请记住,这个新特性不能神奇地消除由类和类加载器引起的内存泄漏。

java8中的元空间总结如下:

PermGen 空间的状况

所有这些内存空间都将被删除。

JVM的参数:PermSize和MaxPermSize将被忽略并给出警告(如果这两个参数是在启动时设置的)。

Metaspace 内存分配模型

大多数分类元数据都分配在本地内存中。

用于描述类元数据的“类别”已经被删除。

Metaspace 容量

默认情况下,类元数据仅受可用本地内存的限制(容量取决于32位或64位操作系统的可用虚拟内存大小)。

新参数(MaxMetaspaceSize)用于限制分配给类元数据的本地内存的大小。如果未指定此参数,元空间将在运行时根据需要动态调整。

Metaspace 垃圾回收

当元数据使用达到“MaxMetaspaceSize”参数的设置值时,将对死类和类加载器进行垃圾收集。

有必要及时监控和调整元空间,以减少垃圾收集频率和延迟。元空间的持续垃圾收集表明可能存在由类和类加载器或不正确的大小设置导致的内存泄漏。

Java 堆内存的影响

一些杂项数据已经转移到Java堆空间。升级到JDK8后,你会发现Java堆空间增加了。

Metaspace 监控

可以从HotSpot1.8的详细GC日志输出中获得元空间的使用情况。

用b75版本测试时更新了Jstat和JVisualVM两个工具,但还是能看到旧的PermGen空间。

在理论上已经得到了充分的解释。让我们通过“泄漏”程序来观察新的内存空间.

PermGen vs. Metaspace 运行时比较

为了更好地理解元空间内存空间的运行时行为,

将测试以下场景:

1.使用JDK1.7运行Java程序,监控并耗尽默认设置的PermGen内存空间85MB。

2.用JDK1.8运行Java程序,监控新元空间内存空间的动态增长和垃圾收集过程。

3.用JDK1.8运行Java程序,模拟“MaxMetaspaceSize”参数设置的128MB元空间内存空间耗尽的情况。

首先,建立一个模拟PermGen OOM的代码。

公共类ClassA {

公共void方法(字符串名称){

//什么都不做

}

}

上面是一个简单的ClassA,编译成class字节码放在D:/classes下。在测试代码中,使用URLClassLoader加载该类型,并将上面的类编译成class。

/**

*模拟房间

*

*/

公开课OOMTest {

公共静态void main(String[] args) {

尝试{

//准备url

URL url=新文件(' D:/classes ')。旅游()。toURL();

URL[]URLs={ URL };

//获取关于类型加载的JMX接口

ClassLoadingMXBean loading bean=management factory . getclassloadingmxbean();

//用于缓存类加载器

ListClassLoader class loaders=new ArrayList class loader();

while (true) {

//加载类型并缓存类加载器实例

ClassLoader classLoader=新的URL class loader(URL);

class loaders . add(class loader);

class loader . load class(' class a ');

//显示数量信息(已加载的类型总数,当前仍然有效的类型数,已卸载的类型数)

system . out . println(' total:' loading bean . gettotalloadedclasscount());

system . out . println(' active:' loading bean . getloadedclasscount());

system . out . println(' unloaded:' loading bean . getunloadedclasscount());

}

} catch(异常e) {

e . printstacktrace();

}

}

}

虚拟机参数设置如下:-verbose -verbose:gc

设置-verbose参数是为了获取有关类型加载和卸载的信息。

-verbose:gc被设置为获取有关垃圾收集的信息。

JDK 1.7 @64-bit PermGen 耗尽测试

Java1.7的默认PermGen空间是85 MB(或者可以用-XX:MaxPermSize=XXXm指定)

从上面的JVM截图可以看出,当加载超过60000个类的时候,PermGen就耗尽了。我们还可以通过程序和GC的输出来观察耗尽的过程。

程序输出(提取部分)

.

[从文件中加载的class a:/D:/classes/]

总计:64887

活跃:64887

已卸载:0

[GC 245041K-213978K(536768K),0.0597188秒]

[完整GC 213978K-211425K(644992K),0.6456638秒]

[GC 211425K-211425K(656448K),0.0086696秒]

[完整GC 211425K-211411K(731008K),0.6924754秒]

[GC 211411K-211411K(726528K),0.0088992秒]

..

Java . lang . out of memory error:perm gen space

JDK 1.8 @64-bit Metaspace大小动态调整测试

Java的元空间:无限制(默认)

从上面的截图可以看出,JVM元空间进行了动态扩展,本地内存的使用量从20MB增加到646MB,以满足程序中不断增加的类数据内存占用需求。我们还可以观察到JVM的垃圾收集事件——试图销毁死去的类或类加载器对象。但是由于我们程序的泄露,JVM别无选择,只能动态扩展Metaspace的内存空间。该程序加载了超过100,000个没有OOM事件的类。

JDK 1.8 @64-bit Metaspace 受限测试

Java的元空间:128 MB(-xx:maxmetaspace size=128m)

从上面的JVM截图可以看出,当加载超过20000个类时,Metaspace就被耗尽了;非常类似JDK1.7运行时。我们还可以通过程序和GC的输出来观察耗尽的过程。另一个有趣的现象是,保留的本机内存是设置的最大大小的两倍。这可能表明,如果可能,我们可以微调元空间容量的大小策略,以避免本地内存的浪费。

从Java程序的输出中可以看到下面的异常。

[从文件中加载的class a:/D:/classes/]

总计:21393

活跃:21393

已卸载:0

[垃圾收集(元数据垃圾收集阈值)64306K-57010K(111616K),0.0145502秒]

[完整垃圾收集(元数据垃圾收集阈值)57010K-56810K(122368K),0.1068084秒]

Java . lang . out of memory error:Metaspace

设置MaxMetaspaceSize时,这个空间的内存仍然会耗尽,从而导致“Java . lang . out memory error:metadata space”错误。因为类加载器的泄漏仍然存在,而Java通常不希望无限消耗原生内存,所以设置一个类似MaxPermSize的限制似乎是合理的。

总结

1.之前,不管是否需要,JVM都会吃掉那个空间.如果设置过小,JVM会死;如果设置得太大,JVM会浪费这些内存。理论上,现在可以完全忽略这一点,因为JVM会在运行时自动调整到“合适的大小”;

2.提高全GC的性能。在完全GC期间,不需要在元数据和元数据指针之间进行扫描。不要小看这几纳秒;

3.隐患是,如果程序出现内存泄漏,像OOMTest一样,不断扩展metaspace的空间,会导致机器内存不足,需要进行调试和监控。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: