fastjson反序列化使用不当导致内存泄露

分析一个线上内存告警的问题时,发现了造成内存告警的原因是使用fastjson不当导致的。
分析dump发现com.alibaba.fastjson.util.IdentityHashMap$Entry对象比较多。

查找相关文档:

  1. fastjson IdentityHashMap 内存泄漏排查 (这篇文档分析描述的情况与我们遇到的问题的原因一样,是使用com.alibaba.fastjson.util.ParameterizedTypeImpl不当导致的)
  2. fastjon官方在很早的版本就修复过类似的问题,https://github.com/alibaba/fastjson/issues/849 ,相关代码:https://github.com/alibaba/fastjson/commit/ef50a5b756a6cab1ab753f4a661bdfb0ccbd6b7e ,他们修复的这个bug是针对com.alibaba.fastjson.TypeReference,这个类实际也是基于com.alibaba.fastjson.util.ParameterizedTypeImpl的。

问题产生的原因分析:

  1. com.alibaba.fastjson.ParserConfig定义一个字段用于缓存不同类的反序列化器,使用的是IdentityHashMap(IdentityHashMap使用的是==比较key的值,不同于HashMap使用equals比较),缓存是以Type为key:
    private final IdentityHashMap<Type, ObjectDeserializer> deserializers = new IdentityHashMap<Type, ObjectDeserializer>();
  2. 而我们的业务代码是在调用一个接口后将结果反序列化,然后每次都去创建一个ParameterizedTypeImpl实例,而fastjson针对每次创建的PamrameterizedTypeImpl都会作为一个key加入到deserizers中进行缓存。
    // ... ...
    ParameterizedTypeImpl type = new ParameterizedTYpeImpl(new Type[]{ SomeInfo.class }, null, CommonVO.class);
    CommonVO<SomeInfo> result = (CommonVO<SomeInfo>)JSON.parseObject(jsonString, type);

    所以,随着不断的请求发起,内存泄漏产生了。(上面提到的fastjson自身的bug修复就是针对不同的类型又采用了ConcurrentHashMap基于Class进行了一次缓存)

问题修复:
方法一:
由于这里主要只是因为泛型才用了ParameterizedTypeImp,并且只有这一处,所以可以简单粗暴把这个定义为局部变量的type改为private static final的全局变量就可以避免内存泄漏了

private static final ParameterizedTypeImpl SOME_INFO_TYPE = ...

方法二:
使用com.alibaba.fastjson.TypeReference。

JSON.parseObject(json, new TypeReference<CommonVO<T>>(SomeInfo.class) {});

https://github.com/alibaba/fastjson/wiki/TypeReference

原文地址:https://www.cnblogs.com/liqipeng/p/11665889.html

时间: 2024-10-11 03:53:15

fastjson反序列化使用不当导致内存泄露的相关文章

TransitionDrawable使用不当导致内存泄露

最近要做类似网易云音乐背景高斯模糊的效果, 同时也想让背景变化时不要那么生硬, 就是下面这个效果 Google一番后决定用TransitionDrawable, 由于是配合UniversalImageLoader使用, 所以只需要实现一个BitmapDisplayer作为UIL的配置项就行了. 最初的代码是这样写的 private static class DrawableFadeDisplayer implements BitmapDisplayer { private final int d

Andorid 内存溢出与内存泄露,几种常见导致内存泄露的写法

内存泄露,大部分是因为程序的逻辑不严谨,但是又可以跑通顺,然后导致的,内存溢出不会报错,如果不看日志信息是并不知道有泄露的.但是如果一直泄露,然后最终导致的内存溢出,仍然会使程序挂掉.内存溢出大部分是关于图片的请求,然后又没有及时的释放内存,而导致的内存泄露. 下面是几种常见的导致内存泄露的写法.有些是收集的别的地方的,我也是看到才知道自己写错了,分享一下吧 1.单例造成的内存泄漏 大家都喜欢用Android的单例模式,不过使用的不恰当的话也会造成内存泄漏.因为单例的静态特性使得单例的生命周期和

hadoop1.0 TaskTracker因为分布式缓存导致内存泄露的一次问题排查

上周五同事到公司说凌晨的时候有值班同事打电话给他,有部分job卡住了,运行了很长时间都没运行完成,由于是凌晨,他没来得及详细的查看日志,简单的把有问题的tasktracker重启了一下,只有一个节点的TaskTracker进程停掉,让我查一下具体是什么问题.以下是排查过程: 1.登陆到停掉TT进程的处理机 (1).查看磁盘空间 磁盘没有出现空间不足的情况. (2).top查看负载和内存使用情况: 根据上图看出内存和负载都不算高,也不存在僵尸进程. 2.查看进程日志 1.log4j日志: 2014

BingMap频繁Add Pushpin和Delete Pushpin会导致内存泄露

最近在做性能测试的时候发现BingMap内存泄露(memory leak)的问题,查找了一些国外的帖子,发现也有类似的问题,但是没有好的解决办法. https://social.msdn.microsoft.com/Forums/en-US/3226f255-2ae1-4718-b848-5f24e76b64b0/your-pushpins-are-broken-addremove-leads-to-memory-leak?forum=bingmapsajax 经过一番尝试,找到了一个折中的解决

Handler导致内存泄露分析

Handler mHandler = new Handler() {    @Override    public void handleMessage(Message msg) {            // do something.    }}```当我们这样创建`Handler`的时候`Android Lint`会提示我们这样一个`warning: In Android, Handler classes should be static or leaks might occur.`. 一

Context使用不当造成内存泄露

一般来说,视频同步指的是视频和音频同步,也就是说播放的声音要和当前显示的画面保持一致.想象以下,看一部电影的时候只看到人物嘴动没有声音传出:或者画面是激烈的战斗场景,而声音不是枪炮声却是人物说话的声音,这是非常差的一种体验. 现在游戏市场分为,pc端,移动端,浏览器端,而已移动端和浏览器端最为接近.都是短平快的特殊模式,不断的开服,合服,换皮.如此滚雪球! 那么在游戏服务器架构的设计方面肯定是以简单,快捷,节约成本来设计的. http://www.cnblogs.com/nsrtuj/ 最近接到

memset函数导致内存泄露的问题

我们一般常说的内存泄漏是指堆内存的泄漏.程序从堆中分配的内存使用完毕后必须显式释放,否则这块内存就不能被再次使用,即这块内存泄漏了.内存泄漏导致软件在运行过程中占用越来越多的内存,程序的效率会越来越低,从而影响用户的体验,失去市场竞争力.  为了预防内存泄漏我们要求程序使用malloc.new等函数从堆中分配的内存必须在使用完后调用free.delete函数释放该内存.但是如果指向该内存指针的值被修改了,不再指向该内存了,那么即使调用free.delete函数也不会释放该内存,memset函数

引用计数gc机制使用不当导致内存泄漏

上一篇文章找同事review了一下,收到的反馈是铺垫太长了,我尽量直入正题,哈哈 最近dbd压测时发现内存泄漏,其实这个问题去年已经暴露了,参见这篇博客[压测周].当时排查不够仔细,在此检讨下.关于dbd的内存问题,还有这篇博客讨论线程安全,以及这篇博客讨论临时变量的处理.当时还存了一个尾巴,因为用到关联数组进行脏数据管理,这部分数据是怎么释放的一直没搞明白.今天算是搞明白了,这个内存泄漏的bug也源于此. 基于引用计数的gc机制,应该是在引用计数为0的时候释放内存的,lpc也基本没有例外.具体

静态变量导致的内存泄露

public  class MainActivity extends Activity{                private static final String TAG = "MainActivity";             private static Context sContext;                   @Override             protected void onCreate(Bundle savedInstanceState)