Skip to content

fix: cache ObjectWriter created in switch block of getObjectWriterInt…#7627

Open
Elin-Zhou wants to merge 1 commit into
alibaba:mainfrom
Elin-Zhou:fix/objectwriter-cache-miss-guava-multimap
Open

fix: cache ObjectWriter created in switch block of getObjectWriterInt…#7627
Elin-Zhou wants to merge 1 commit into
alibaba:mainfrom
Elin-Zhou:fix/objectwriter-cache-miss-guava-multimap

Conversation

@Elin-Zhou
Copy link
Copy Markdown

@Elin-Zhou Elin-Zhou commented Apr 21, 2026

What this PR does / why we need it?

ObjectWriterProvider.getObjectWriterInternal() 中,switch/case 块通过 GuavaSupport.createAsMapWriter() 为 Guava Multimap 类型(LinkedListMultimapArrayListMultimapHashMultimapLinkedHashMultimapTreeMultimap)创建了 ObjectWriter,但创建后没有写入缓存

cache.putIfAbsent() 仅存在于后续的 if (objectWriter == null) 分支中(line 718),而此时 objectWriter 已被 switch 赋值为非 null,该分支永远不会执行。

这导致每次 JSON.toJSONString(guavaMultimap) 都会重新创建 AsMapWriter,其构造函数通过 LambdaMiscCodec.createFunction()LambdaMetafactory.metafactory()invokestatic 调用,绕过了 JVM 的 ConstantCallSite 缓存)生成新的 Lambda Hidden Class。这些 Hidden Class 被 ClassLoader 持有,无法被 GC 回收,造成 Metaspace 持续线性增长。

生产环境每分钟调用约 15 次 JSON.toJSONString(LinkedListMultimap)),Metaspace 以约 200MB/天的速度增长,2~3 天耗尽 1024MB 上限。

Summary of your change

getObjectWriterInternal() 的 switch 块之后增加了缓存写入逻辑:

if (objectWriter != null) {
    ObjectWriter previous = fieldBased
            ? cacheFieldBased.putIfAbsent(objectType, objectWriter)
            : cache.putIfAbsent(objectType, objectWriter);
    if (previous != null) {
        objectWriter = previous;
    }
    return objectWriter;
}

复用了同方法中已有的 putIfAbsent + previous 缓存模式(module 路径 line 670、通用路径 line 725)。修复后,ObjectWriter 在首次创建时写入缓存,后续调用在外层 getObjectWriter()cache.get() 直接命中,不再进入 getObjectWriterInternal() 重复创建。

jstat -class 验证结果:

指标 修复前 修复后
Loaded 类数(15 秒窗口) 1709 → 3109(每秒 +100) 1409 稳定不变(+0)
Unloaded 类数 0 0

新增测试GuavaMultimapWriterCacheTest.java,共 11 个用例):

  • 5 种 Guava Multimap 类型的缓存命中测试(assertSame 验证两次 getObjectWriter() 返回同一实例)
  • 5 种类型的序列化正确性测试
  • 基于 ClassLoadingMXBean 的 Metaspace 泄漏回归测试

Please indicate you've done the following:

  • Made sure tests are passing and test coverage is added if needed.
  • Made sure commit message follow the rule of Conventional Commits specification.
  • Considered the docs impact and opened a new docs issue or PR with docs changes if needed.

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Apr 21, 2026

CLA assistant check
All committers have signed the CLA.

Comment thread core/src/test/java/com/alibaba/fastjson2/writer/GuavaMultimapWriterCacheTest.java Outdated
@Elin-Zhou Elin-Zhou force-pushed the fix/objectwriter-cache-miss-guava-multimap branch from e4bb9fc to f905f48 Compare April 27, 2026 09:50
@Elin-Zhou Elin-Zhou requested a review from wenshao May 4, 2026 06:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants