fastjson class泄漏

前端之家收集整理的这篇文章主要介绍了fastjson class泄漏前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

问题描述

fastjson在jetty容器中序列化HttpServletRequest会导致class泄漏,严重时会导致Meta区溢出,导致无限FGC。

fastjson序列化流程

fastjson通过动态生成代码提高序列化速度,序列化逻辑如下:

Stringserialize(Objectobject){

//先看是否已经存在对应的serializer
Serializerserializer=serializerCache.get(object.getClass());

if(serializer==null){

//通过动态生成代码的方式,创建新的序列器类
Class<?>serializerClass=createSerializerClass(object.getClass());
serializer=serializerClass.newInstance();
serializerCache.put(object.getClass(),serializer);

}
returnserializer.serialize(object);

}

如果传入的object类型是org.eclipse.jetty.server.Request,serializerClass.newInstance会出现异常。因此每次序列化org.eclipse.jetty.server.Request,都会生成一个serializerClass。即出现了class泄漏。

PS: org.eclipse.jetty.server.Request是jetty中HttpServletRequest的实现类,下面简称Request

newInstance()为什么会失败?

fastjson生成的serializerClass结构如下:

importorg.eclipse.jetty.server.Request;

classSerializer_XXX{

//Request中每个字段对应一个xxx_asm_field_type字段
Typecontext_asm_field_type;
TypeuserIdentityScope_asm_field_type;
//其他字段省略...

//构造函数
Serializer_XXX(){

context_asm_field_type=getFieldType(Request.class,"context");
userIdentityScope_asm_field_type=getFieldType(Request.class,"userIdentityScope");
//其他字段忽略...

}
}

构造函数会执行失败,原因是找不到org.eclipse.jetty.server.Request。

为什么找不到类?

问题涉及到的3个classloader,它们的结构如下:
ServerClassLoader -> WebAppClassLoader -> AsmClassLoader

Request的classloader是ServerClassLoader,Serializer_XXX的classloader是AsmClassLoader。


按照类加载的约定,加载Request类的流程如下:

wKiom1k-Tgax0r6dAAFB1aLwjBE321.png-wh_50

理论上Request是可以成功加载的。问题出在WebAppClassLoader,它违反了类加载的约定,没有让parent加载,而是自己直接加载,结果找不到,就直接抛ClassNotFoundException。
WebAppClassLoader的行为是可配置的,如果启动参数org.eclipse.jetty.server.webapp.parentLoaderPriority是true,它就会先让parent找,否则就自己找,默认是false

fastjson的问题在哪里?

fastjson实际是有考虑类加载的问题的,它是判断Request的ClassLoader是不是AsmClassLoader或AsmClassLoader的祖先。但是由于WebAppClassLoader违背了类加载的约定,fastjson的判断就变得不可靠了。

猜你在找的Json相关文章