大量DelegatingClassLoader类加载器,导致Perm区溢出

当使用Java反射时,Java虚拟机有两种方法获取被反射的类的信息。它可以使用一个JNI存取器;如果使用Java字节码存取器,则需要拥有它自己的Java类和类加载器(sun/reflect/GeneratedMethodAccessor类和sun/reflect/DelegatingClassLoader),这些类和类加载器使用本机内存。字节码存取器也可以被JIT编译,这样会增加本机内存的使用。如果Java反射被频繁使用,会显著地增加本机内存的使用。

Java虚拟机会首先使用JNI存取器,然后在访问了同一个类若干次后,会改为使用Java字节码存取器。这种当Java虚拟机从JNI存取器改为字节码存取器的行为被称为膨胀(Inflation)。Inflation机制提高了反射的性能,但是对于重度使用反射的项目可能存在隐患,它带来了两个问题:(1)初次加载的性能损失;(2)动态加载的字节码导致PermGen持续增长。幸运的是,我们可以通过一个设置-Dsun.reflect.inflationThreshold=N控制这种行为,sun.reflect.inflationThreshold会告诉Java虚拟机使用JNI存取器多少次。如果设为0,则总是使用JNI存取器。

正常情况下,在Java中类是永久存在的。所以一旦类被加载,他们将一直停留在内存中,即便其所在应用服务器端已经停止运行。像cglib这样的动态类产生库,在他们动态创建了大量类之后,会使用大量永久代内存空间。在运行时创建的代理类被广泛地使用,当单个类定义被用于产生多个实例时,创建新的代理类将会很容易。Spring和Hibernate经常产生某个类的代理,这些代理类被类加载器加载,产生的类定义从不被清理,导致永久性堆空间迅速填满。

关掉Inflation会带来一定程度上的性能损失,因此不到万不得已的情况下并不要将其关闭,sun.reflect.inflationThreshold的默认值在不同的实现版本中有不同的值,例如在IBM Developer Kit for Java 5.0 的默认值为15。可以尝试将这个值设置大一点,例如100。虽然Java中的class放在perm区中默认是不被GC的,但是我们可以指定让他也参与GC,通过打开两个参数:-XX+CMSClassUnloadingEnabled -XX+UseConcMarkSweepGC,这样GC的时候在perm区中的垃圾class元数据也会被回收掉,从而释放perm区的内存空间。JDK8已经没有了perm区的概念,类的元数据被存放在Metaspace中,会自动进行垃圾回收,卸载掉不再使用的类。

另外需要注意的是,检查JVM启动参数中是否使用了-Xnoclassgc,如果增加了这个参数,class是不会被GC掉的,需要去掉这个参数。

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`java.lang.OutOfMemoryError: PermGen space` 和 `java.lang.OutOfMemoryError: Metaspace` 是Java内存溢出异常的两个常见变种,它们通常发生在Java虚拟机(JVM)试图动态扩展其方法时。 1. **PermGen Space** (在Java 7之前): 这是存储常量池、类信息、接口信息和编译器产生的内部表示的地方。当应用创建大量临时类(如反射操作)或使用大量的内嵌套类,或者缓存了大量的字节码时,可能会导致 PermGen溢出。 ```java // 示例代码可能触发PermGen溢出 for (int i = 0; i < Integer.MAX_VALUE; i++) { Class<?> tempClass = generateTempClass(); } ``` 2. **Metaspace** (从Java 8开始): Java 8引入了元空间(Metaspace),取代了原来的PermGen空间。Metaspace用于存储运行时常量池、类型信息和接口信息。如果应用中有大量的本地变量表(LocalVariableTable)、字段信息(FieldInfo)或其他元数据,尤其是在使用Java的模块化系统(Modular System,即Jigsaw)时,可能导致Metaspace溢出。 ```java // 使用大量的泛型或类路径下的大文件也可能触发Metaspace溢出 List<String> largeList = new ArrayList<>(Arrays.asList(new String[Integer.MAX_VALUE])); ``` 解决这两种溢出的方法通常包括: - **调整堆大小**: 通过修改`-Xmx`和`-XX:MaxMetaspaceSize`选项来增加JVM可用的内存。 - **优化代码**: 减少不必要的类生成,避免使用过大的局部数组,限制元数据的数量。 - **使用Garbage Collection工具**: 检查并分析GC日志,找出导致内存占用持续增长的原因。 - **考虑使用JVM参数**:`-XX:+UseCompressedOops` 可以减少Metaspace的需求,但可能对某些应用程序性能有影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值