读书人

网站持久代引发Full GC有关问题分析

发布时间: 2013-07-16 22:38:05 作者: rapoo

网站持久代引发Full GC问题分析
JVM分代使用内存量内存总量持久代117M-125M128M新生代220M-225M256M旧生代800M-1G1792M

注:明显看出,新生代以及持久代,内存使用较为紧张,旧生代较为宽裕。

l? Young GC

网站持久代引发Full GC有关问题分析

上图就是在10个线程并发访问wholesaledetail页面,load日志中的内容,问题应该是出现在这些类的加载上。我们debug一下,看看具体情况。

我们debug Classloader这个类的构造器,一次访问是有哪些classloader构造出来,最终debug到 DelegatingClassLoader,结合load日志,发现这个classloader加载后就会有 GeneratedSerializationConstructorAccessor被加载。依据堆栈查看调用信息。

我们看到ReflectionConverter的中的一段代码:

final Object result = instantiateNewInstance(context, reader.getAttribute(mapper.attributeForReadResolveField()));

ReflectionConverter是XStream的反射转换器,转换器是用来编码或解码Java对象的,也就是负责java对象和xml直 接的转换。instantiateNewInstance使用来初始化类的实例的,其中 reader.getAttribute(mapper.attributeForReadResolveField())就是 WholesaleProductPriceXstreamDTO类。

instantiateNewInstance方法中会先去context当中取这个类的实例,如果没有将会使用反射构造出类的实例,在构造实例时,他们创建新的类加载器,并执行下面的一段代码:

Constructor customConstructor = reflectionFactory.newConstructorForSerialization(type, javaLangObjectConstructor);

这段代码就是动态字节码创建类构造器的代码,我们debug发现customConstructor对象中正好包含sun.reflect.GeneratedSerializationConstructorAccessor对象。

而这段代码是在我们的业务二方库biz.wsproduct中调用的:

XStream xstream = new XStream();

xstream.alias(“root”, List.class);

xstream.alias(“record”, WholesaleProductPriceXstreamDTO.class);

问题很清楚了,就是这个XStream,业务代码中错误的new这个类,造成每次执行到这段代码都需要执行上面讲述的一段逻辑,都会load GeneratedSerializationConstructorAccessor类。

而且众所周知,wholesale detail pv巨大(200w以上),大量的类被加载,应该是造成PermGen使用吃紧的原因,而且由于是创造一个新的类加载器,这样一来一次访问结束,就可以回 收这个类加载器,回收其中的类信息,释放部分PermGen空间。这样我们就看到大量的unload出现,而且PermGen虽然空间紧张,但是从未 OOM的问题也就很容易解释了。

整体的堆栈信息如下(部分堆栈信息省略):

Daemon Thread [TP-Processor39] (Suspended)

DelegatingClassLoader(ClassLoader).<init>(ClassLoader) line: 207

DelegatingClassLoader.<init>(ClassLoader) line: 54

MethodAccessorGenerator.generate(Class, String, Class[], Class, Class[], int, boolean, boolean, Class) line: 377

MethodAccessorGenerator.generateSerializationConstructor(Class, Class[], Class[], int, Class) line: 95

ReflectionFactory.newConstructorForSerialization(Class, Constructor) line: 313

Sun14ReflectionProvider.getMungedConstructor(Class) line: 61

Sun14ReflectionProvider.newInstance(Class) line: 40

ReflectionConverter.instantiateNewInstance(UnmarshallingContext, String) line: 145

ReflectionConverter.unmarshal(HierarchicalStreamReader, UnmarshallingContext) line: 87

XStream.unmarshal(HierarchicalStreamReader, Object, DataHolder) line: 521

XStream.unmarshal(HierarchicalStreamReader, Object) line: 509

XStream.fromXML(Reader) line: 475

XStream.fromXML(String) line: 468

WholesaleProductPriceXstreamHelper.convertXmlToWholesaleProductPriceDtoList(String) line: 55

WholesaleDetailUtil.getPriceDetailDTOFormProduct(WsProductDO, String) line: 404

WholesaleDetailUtil.getProductInfoDTOFromProduct(WsProductDO, String) line: 158

WholesaleProductDetail.process(RunData, TemplateContext) line: 282

WholesaleProductDetail(BaseDetailScreen).execute(RunData, TemplateContext) line: 73

WholesaleProductDetail(TemplateModule).execute(RunData) line: 38

解决方案:

解决方案比较简单,我们将XStream的设置成static变量,保证JVM当中只有一个这样的实例,在static块当中初始化,代码如下:

??? private static XStream xstream = null;

??? static {

??????? xstream = new XStream();

??????? xstream.alias(“root”, List.class);

?xstream.alias(“record”, WholesaleProductPriceXstreamDTO.class);

??? }

?

解决效果:

根据最新的Dragoon监控日报显示:

Full GC的次数由原先的647次降至157次,

应用暂停时间由原来的1943232.0 ms (30分钟左右)降至488444.0 ms (8分钟左右),大大缩短了集群的暂停时间,基本解决问题。

读书人网 >编程

热点推荐