标签:safe lin this should static 项目 wsdl 问题 overwrite
多图预警!
从JVisualVM的监控视图中,我们可以直观的看出每隔一分钟都会出现线程数飙升、类加载数阶梯式增长的情况。
随着类加载数的增长,Metaspace空间逐步从60M增长到100M,出现内存溢出,导致jvm频繁触发full GC,消耗大量CPU资源。
Task类 run方法代码:
红框部分为新增代码,具体实现如下:
主要逻辑是与底层组件通信查询运行状态,然后根据结果更新状态。直接排除DAO操作的嫌疑,抽取与通信部分,整理成单独的测试代码:
步骤: 1. 设置jvm参数 : -verbose:class 打印类加载信息
2. 清理控制台日志,调试代码。
调试过程中,我发现每次循环都会有新的类被加载:
而这些类都是在下面这行代码运行之后加载的。
结合类加载信息以及sendRequest方法的实现,基本确认问题是由JaxbUtil处理xml、JavaBean的相互转换引起。
继续调试分析,发现JAXBContext对象初始化时会动态加载class,而JaxbUtil每次调用都会重新创建一个JAXBContext。
问题根因既已找到,解决思路自然清晰明确。
考虑到jdk中已有JAXB工具类提供xml和javaBean的互转,借鉴源码发现JAXB使用弱引用Cache对象来缓存JAXBContext。
/** * Cache. We don‘t want to prevent the {@link Cache#type} from GC-ed, * hence {@link WeakReference}. */ private static volatile WeakReference<Cache> cache; /** * Obtains the {@link JAXBContext} from the given type, * by using the cache if possible. * * <p> * We don‘t use locks to control access to {@link #cache}, but this code * should be thread-safe thanks to the immutable {@link Cache} and {@code volatile}. */ private static <T> JAXBContext getContext(Class<T> type) throws JAXBException { WeakReference<Cache> c = cache; if(c!=null) { Cache d = c.get(); if(d!=null && d.type==type) return d.context; } // overwrite the cache Cache d = new Cache(type); cache = new WeakReference<Cache>(d); return d.context; }
结合应用的实际场景,上面的实现避免了短时间频繁创建JAXBContext。但是弱引用Cache在无引用的情况下会很快被GC回收,所以每次定时任务都会重新生成context;并且Cache对象只能存储一个context,在定时任务的运行过程中可能由于其他接口通信导致context切换。综上,JAXB的实现也无法满足当前应用的需要。
没有现成的解决方案,只好自己写一个。
由创建JAXBContext引起问题,那就延长对象的生命周期,减少新建对象。对于相同的Class,可以使用同一个context对象与xml互相转换。由于vag的接口个数有限, 其xml报文格式并不多,因此,维护一个static Map<Class<?>, JAXBContext>来存储context对象占用的内存并不多。考虑到与vag通信属于并发执行,使用ConcurrentHashMap实现保证并发安全。
最终代码如下:
将之前的测试代码模拟定时任务略微修改,每隔10s执行一次,重复50次。
开启JVisualVM监视视图,从图中可以明确的看出类装载数在第一次循环时就已接近最大值,后续过程中只加载了极少数量的class,证明这种方案确实可行。
使用修改后的代码运行整个项目,16小时后的监视图像显示:类加载数保持稳定,MetaSpace大小几乎无变化。
另外,前段时间还使用-verbose:class 参数排查出Apache CXF生成的webservice客户端重复初始化引起的OOM问题的原因。客户端初始化的过程中也会根据wsdl文件动态生成class并加载,因此,使用CXF客户端代码时,应尽量使用单例模式。
标签:safe lin this should static 项目 wsdl 问题 overwrite
原文地址:http://www.cnblogs.com/tylorliu/p/6978049.html