首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

容易分析cglib引起的PermSize Space内存溢出

2012-10-30 
简单分析cglib引起的PermSize Space内存溢出上段时间有台机器发生了 java.lang.OutOfMemoryError: PermGen

简单分析cglib引起的PermSize Space内存溢出
上段时间有台机器发生了 java.lang.OutOfMemoryError: PermGen space 内存溢出的异常,当时大概判断了原因后就把 MaxPermSize 配置调高后,就把问题解决了,不过空下时间后还是需要继续把review代码。

一般来说PermSize Space OOM的话,第一种可能就是方法区溢出,第二种就是运行时常量池溢出,第二种查看后基本排除掉,问题就应该出现在方法区的溢出,方法区用于存放class的相关信息,如类名,访问修饰符,常量池,字段描述,方法描述等等,对于这个区域的溢出,基本上都是运行时产生大量的类填满了整个方法区,直到溢出。
spring aop中都是使用到了cglib这类字节码的技术,动态代理的类越多,就需要越多的方法区来保证动态生成的class可以加载入到内存中去,下面的例使用cglib直接进行动态代理产生大量的动态类,然后使用jconsole进行观察。

首先将本机的jvm配置为 -XX:PermSize=64M -XX:MaxPermSize=64M ,给到PermSize最大为64M的内存

?

public?class?PermgenOOM?{

????public?static?void?main(String[]?args)?throws?InterruptedException?{
????????int?i=0;
????????while(true){
????????????Enhancer?enhancer?=?new?Enhancer();
????????????enhancer.setSuperclass(Product.class);
????????????enhancer.setUseCache(false);//?关闭CGLib缓存,否则总是生成同一个类
????????????enhancer.setCallback(new?MethodInterceptor()?{????????????????
????????????????@Override
????????????????public?Object?intercept(Object?obj,?Method?method,?Object[]?args,
????????????????????????MethodProxy?methodproxy)?throws?Throwable?{
????????????????????//?TODO?Auto-generated?method?stub
????????????????????return?methodproxy.invokeSuper(obj,args);
????????????????}
????????????});
????????????enhancer.create();
????????????Thread.sleep(100);
????????}
????}
}

?

很快,系统就抛出了 java.lang.OutOfMemoryError: PermGen space
内存池peimgen的情况


容易分析cglib引起的PermSize Space内存溢出

加载类的情况


容易分析cglib引起的PermSize Space内存溢出

并且在方法区中,一个类如果要被垃圾收集器回收掉,判断的条件是非常苛刻的,很多人都把方法区称为“永久区”(Permanent Generation),但据说2者在本质上是不一致的,另外还有称呼为“非堆区”,不纠结这个了。

再看看enhancer.setUseCache(false),如果选择为true的话,那么就使用和更新一类具有相同属性生成的类的静态缓存,而不会在同一个类文件还继续被动态加载并视为不同的类,这个其实跟类的equals()和hashCode()有关,它们是与cglib内部的class cache的key相关的。

将上面的程序 enhancer.setUseCache(false) 改为 enhancer.setUseCache(ture)

?

public?class?PermgenOOM?{

????public?static?void?main(String[]?args)?throws?InterruptedException?{
????????int?i=0;
????????while(true){
????????????Enhancer?enhancer?=?new?Enhancer();
????????????enhancer.setSuperclass(Product.class);
????????????enhancer.setUseCache(true);//?或者不写,默认值就是true
????????????enhancer.setCallback(new?MethodInterceptor()?{????????????????
????????????????@Override
????????????????public?Object?intercept(Object?obj,?Method?method,?Object[]?args,
????????????????????????MethodProxy?methodproxy)?throws?Throwable?{
????????????????????//?TODO?Auto-generated?method?stub
????????????????????return?methodproxy.invokeSuper(obj,args);
????????????????}
????????????});
????????????enhancer.create();
????????????Thread.sleep(100);
????????}
????}
}

?

内存池peimgen的情况


容易分析cglib引起的PermSize Space内存溢出

加载类的情况


容易分析cglib引起的PermSize Space内存溢出

可以发现内存池peimgen和加载类的情况并没有呈现直线上涨,已经他们一直都使用者动态类生成类的静态缓存,但是这种动态创建类使用静态缓存在一些情况下并不适合需求。

热点排行