[alibaba/fastjson]ParserConfig的IdentityHashMap存在内存泄露

2025-11-24 363 views
3

String text = "{\"modules\":{\"name\": \"alibaba\"}}";

for (int i=0; i<2; i++) {
        L1<?> r1 = JSONObject.parseObject(text, new TypeReference<L1<L2>>(){});
}
     // debug
L1<?> r1 = JSONObject.parseObject(text, new TypeReference<L1<L2>>(){});

发现了IdentityHashMap的的System.identityHashCode(key);产生了变化,导致了缓存的不命中,后续继续追加到内存里面去,这就是内存爆涨的元凶。

回答

2

你使用的版本号是多少?这个问题应该是修复过的.

6

1.2.25,1.2.33 都有

8

IdentityHashMap的key使用的是Class,如果使用ClassName应该能避免这个问题。 @wuwen5

9

@kimmking 这个问题应该是在TypeReference解决掉的,IdentityHashMap最终的key是Type对象类型,固定的,单参和多参的时候是缓存在ConcurrentHashMap中的,这种测试场景下不会一直递增的。

@zilong 建议你再debug仔细检查下,比如循环10次,检查key的地址, 我没有重现你说的问题,如果有问题你可以再提供详细信息.

2

see #849

9
1281 好像我的问题和这个差不多,能帮忙看看吗?生产环境跪了几天了,一直没人回复我
2

@zilong 确认了这个问题在安卓的环境下存在,不过你之前测试的版本是1.2.24 \1.2.33 确认下你也是在安卓下验证的么?

安卓环境下建议使用带参数的写法. 参考单参数 和多参数的例子. https://github.com/alibaba/fastjson/wiki/TypeReference.

5

IdentityHashMap 是用native Hash的,真有问题,仔细debug就能发现了这个问题了(环境JDK8)。@wuwen5 你找一下高铁

1

所以这个解决了么。。。native Hash虽然能避免空指针异常,但是我们override hashCode就没意义了额。也就是说,如果是自己实现ParameterizedType,并使用JSON.parseObject(str, 自定义的type实现) 来解析,还是会造成这种内存泄漏。

1

同样也遇到了相似的问题…… **One instance of "java.lang.ref.Finalizer" loaded by "" occupies 396,992,088 (63.02%) bytes. The instance is referenced by com.alibaba.fastjson.util.IdentityHashMap$Entry @ 0x824d3640 , loaded by "org.apache.catalina.loader.WebappClassLoader @ 0x80627b38".

Keywords org.apache.catalina.loader.WebappClassLoader @ 0x80627b38 java.lang.ref.Finalizer** 这是从线上拉下的dump文件分析结论

4

`private final static Type typeReference = new TypeReference<ESResultVO>() { }.getType();

static {
    ParserConfig.getGlobalInstance().getDeserializer(typeReference);
}

@Test
public void json() {
    ExecutorService executorService = ThreadUtil.newExecutor();
    while (true) {
        for (int j = 0; j < 10; j++) {
            executorService.submit(this::test);
        }
    }
}

private void test() {
    ESResultVO<TaskLogVO> json = JSON
        .parseObject("{\n" + "  \"code\": 0,\n" + "  \"message\": null,\n" + "  \"result\": {\n" + "    \"took\": 16,\n" + "    \"count\": 1,\n" + "    \"list\": [\n"
                     + "      {\n" + "        \"appId\": 4,\n" + "        \"bizNo\": \"\",\n" + "        \"elapsed\": 0,\n" + "        \"endTime\": 1567044743242,\n"
                     + "        \"gmtCreate\": 1567044743242,\n" + "        \"gmtUpdate\": 1567044743242,\n" + "        \"guid\": \"1fac95e9-081e-4e7a-965e-3279b306f1c3\",\n"
                     + "        \"id\": \"bc261686-11ef-461d-9ca0-a7aab09112b2\",\n" + "        \"startTime\": 1567044743242,\n" + "        \"status\": 0,\n"
                     + "        \"taskGuid\": \"3c704084-bc66-448d-86ff-f707f3d38317\",\n" + "        \"taskId\": 74,\n"
                     + "        \"traceId\": \"7b979533f94d48908d8fdd0d386a8400\",\n" + "        \"_score\": 0\n" + "      }\n" + "    ]\n" + "  }\n" + "}",
            typeReference);
}`

这么干可以解决这个问题,是个坑啊。最新的1.2.59,依然存在。有时候爆涨很快,有时候很慢,看运气。

9

1.2.78 依然存在

8

1.2.78 依然存在

老哥,现在有解决方案吗

8

1.2.78 依然存在

老哥,现在有解决方案吗

每创建一次classload, IdentityHashMap就会增长,频繁创建,删除classload 就是一直涨,直到OOM,避免频繁创建classload(如果必须,就缓存classload)