上段时间有台机器发生了 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的情况
加载类的情况
并且在方法区中,一个类如果要被垃圾收集器回收掉,判断的条件是非常苛刻的,很多人都把方法区称为“永久区”(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的情况
加载类的情况
可以发现内存池peimgen和加载类的情况并没有呈现直线上涨,已经他们一直都使用者动态类生成类的静态缓存,但是这种动态创建类使用静态缓存在一些情况下并不适合需求。
分享到:
相关推荐
CGLIB简介CGLIB简介CGLIB简介CGLIB简介CGLIB简介
Cglib代理,也叫做子类代理。在内存中构建一个子类对象从而实现对目标对象功能的扩展。如果想代理没有实现接口的类,就可以使用CGLIB实现。这是一个简单的案例。
基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)...
cglib
开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4...
cglib.zip
赠送jar包:cglib-3.1.jar; 赠送原API文档:cglib-3.1-javadoc.jar; 赠送源代码:cglib-3.1-sources.jar; 赠送Maven依赖信息文件:cglib-3.1.pom; 包含翻译后的API文档:cglib-3.1-javadoc-API文档-中文(简体)版...
cglib包及依赖汉cglib3.1和asm4.2,主要作用是用户代理,代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。...
CGLIB介绍与原理(部分节选自网络) 一、什么是CGLIB? CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要...
cglib 的jar包,用于做动态代理的,但是版本太高不知道会不会有影响
NULL 博文链接:https://zhangyu84849467.iteye.com/blog/2278744
Java JDK代理、CGLIB、AspectJ代理分析比较
CGLIB-DOC,CGLIB说明文件.
cglib-3.2.5.jar、cglib-nodep-3.2.5.jar、cglib-RELEASE_3_2_5.tar.gz(源码)、cglib-RELEASE_3_2_5.zip(源码)
里面包含完整的cglib-nodep-2.2.jar和asm-2.2.3.jar,放心下载
Cglib的jar文件,包含:asm.jar、asm-commons.jar、asm-tree.jar、cglib-2.2.jar 四个jar包
在cglib需要的包,含有asm.jar asm_commons.jar asm-util.jar cglib-nodep.jar
cglib-2.2.2源码
Cglib最新版本的2个jar包,分别是cglib-3.3.0.jar和cglib-nodep-3.3.0.jar,压缩后上传,方便大家使用。
CGLib详细教程 CGLib详细教程 CGLib详细教程