前言
最近项目在进行性能测试,在最后做稳定性测试的过程中出现一个问题:前几个小时 tps 一直很稳定,过了某一个时间点,tps 随着时间的推移不断下降,直到降为 0。观察平台监控,发现内存开销不断上升,通过监控定位到产生问题的代码为一个使用 XStream 的工具类,工具类中使用 XStream 实现了 xml 与 bean 的互相转换。该工具类导致了内存泄露问题,后来百度了一下,找到了产生问题的原因与解决办法,记录一下处理办法。
原因分析
在 Java 中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为 Java 中的内存泄漏,这些对象不会被 GC 所回收,然而它却占用内存。
public static String objectToXml(Object obj) {
XStream xstream = new XStream();
// xstream使用注解转换
xstream.processAnnotations(obj.getClass());
// 启用Annotation
xstream.autodetectAnnotations(true);
return xstream.toXML(obj);
}
工具类中在获取 XStream 对象时每次都使用 new 的方式,然后 Xstream 内部又会 new 一个 CompositeClassLoader 对象,并且 Class.forName 调用该 loader 对象。问题就出现在这个对象上,minor gc 不会回收这种 class loader 对象,每个请求又都会 new 一个 CompositeClassLoader 对象,存在大量可达且无用对象,那就会导致堆空间逐渐被占满,并且产生 full gc。
解决方案
在方法外 new 一个全局静态 XStream 对象,这样 CompositeClassLoader 对象只会被 new 一个,虽然 CompositeClassLoader 对象存在堆区,但是静态 finnal 级别的 XStream 对象不在堆区,因此不存在可达且无用对象,从而 minor gc 会回收这种 class loader 对象。
private static final XStream xstream = new XStream(new DomDriver());
public static String objectToXml(Object obj) {
// xstream使用注解转换
xstream.processAnnotations(obj.getClass());
// 启用Annotation
xstream.autodetectAnnotations(true);
return xstream.toXML(obj);
}
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于