现在ParserConfig和SerializeConfig类中使用了IdentityHashMap来缓存生成的解析器,但它同时也持有了对要解析的类的一个强引用,导致这个类的类加载器被关闭后,GC也无法卸载这些类。因此,我对IdentityHashMap进行了一些改动,使用WeakReference来存放键和值。不过我总感觉这样似乎过于魔改,并且内存压力大时可能会导致频繁重新生成解析器。还请 @wenshao 指点,非常感谢。
[alibaba/fastjson]使用WeakReference储存序列化和反序列化器
回答
动态生产的类不应该是序列化传输的对象哈?
使用场景是这样的:我们的项目里有一个插件机制,为了支持动态加载和卸载插件,使用了每个插件jar一个类加载器的机制。现在的问题是,主模块使用fastjson序列化或反序列化了插件内的类之后,这个类就被fastjson内部的缓存机制引用,导致执行卸载插件操作后,gc无法回收这些类
插件相关的类能单独一个ParserConfig或者SerializeConfig更合适吧?
在我们项目里,序列化逻辑分布在框架中,用于解析请求参数和响应数据,并不在插件里;如果针对插件内的类进行单独处理,就需要修改这些逻辑并且为每一个类检查其类加载器,再为每一个类加载器维护单独的ParserConfig和SerializeConfig,就我个人看法而言,似乎不如直接改fastjson来得方便。也许是我们架构设计上存在问题,我再思考下有没有其他的办法。
不是每个类一个ParserConfig/SerializeConfig,而是每个插件一个SerializeConfig/ParserConfig,插件呢卸载自然也就卸载了
可能我没有描述清楚,使用场景是这样的:框架framework.jar使用parentClassLoader加载,其中包含了fastjson,然后插件plugin.jar(不包含fastjson)由childClassLoader加载,加载后,framework.jar里的代码会扫描classpath,并使用childClassLoader加载plugin.jar中的类A,后续代码会使用fastjson将A序列化。现在的问题在于,framework.jar中的序列化相关的代码并不知道A是从哪里加载的,属于哪个插件。而且,若plugin.jar中的代码使用了fastjson,也会导致无法回收。
后续我们将使用如下方式解决:
修改框架中的序列化逻辑,并针对每一个不同类加载器(不是每一个类)维护单独的ParserConfig和SerializeConfig
对于插件,初始化时即传入ParserConfig和SerializeConfig,插件中的序列化逻辑强制要求使用它们
这样可以避免对fastjson的修改。
不过,如果可以的话,能否开放对IdentityHashMap的访问,让使用者能自行决定是否删除某一条目?