排查FastJson内存溢出需先据OOM类型定方向:堆内(Java heap space)主因大JSON全量加载、深嵌套致char[]/Object[]暴涨;堆外(Metaspace/Direct buffer)主因ParserConfig缓存ParameterizedTypeImpl泄漏或动态类膨胀,应分别用流式解析、TypeReference复用及JVM防护参数治理。

排查对象序列化导致的内存溢出,关键要区分是堆内还是堆外问题,并结合 FastJson 等组件的典型行为来定位。不是所有 OOM 都来自业务代码写错,很多源于序列化过程中的缓存滥用、泛型误用或大 JSON 全量加载。
看错误类型,先定方向
拿到 OutOfMemoryError 日志后,第一眼盯住报错信息:
- java.lang.OutOfMemoryError: Java heap space → 堆内存撑爆,重点查大对象、深嵌套、未分页解析
- java.lang.OutOfMemoryError: Metaspace 或 Direct buffer memory → 堆外问题,关注 ParserConfig 缓存、ParameterizedTypeImpl 泄漏、DirectByteBuffer 持续增长
- GC overhead limit exceeded → 老年代几乎占满,GC 效率极低,往往伴随反序列化高频调用
堆内溢出:重点查 JSON 解析方式
FastJson 默认把整个 JSON 加载成 JSONObject/JSONArray,底层用 char[] 缓冲区,单个字段超长(比如 base64 图片、百万级数组)就会一次性申请几百 MB 内存。
- 用 jstat -gcutil <pid> 观察老年代使用率是否持续 95%+,且 Full GC 后不下降
- 堆 dump 中搜索 [C(char[]) 和 [Ljava.lang.Object;,如果排在前几位,基本锁定是 SerializeWriter.buf 或 JSONArray 内部扩容所致
- 改用 JSONReader 流式解析:对大数组逐条读取,不保留全部结构;服务端加 Content-Length 校验,拒绝超过 10MB 的请求
堆外溢出:重点查泛型与缓存机制
ParserConfig 的 deserializers 是 IdentityHashMap,key 是 Type 实例。每次 new ParameterizedTypeImpl,哪怕类型相同,也会被当成新 key 缓存,导致 native 内存或 Metaspace 持续上涨。
立即学习“Java免费学习笔记(深入)”;
- 用 pmap -x <pid> 或开启 NMT(-XX:NativeMemoryTracking=detail)确认 RSS 远超 -Xmx,但 jmap -heap 显示堆正常
- dump 中搜 ParameterizedTypeImpl 和 IdentityHashMap$Entry,数量随请求线性增长即为泄漏特征
- 修复方法:把泛型 Type 定义为 static final,或统一用 TypeReference<List<SomeInfo>> {},避免运行时反复构造 Type 实例
启动时加基础防护参数
别等出事才补救,上线前必须配置:
- -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/dumps/:OOM 自动落盘,方便后续用 MAT 分析
- -XX:MaxMetaspaceSize=256m:防动态类加载失控(尤其用了大量泛型或代理)
- -Dfastjson.parser.autoTypeSupport=false(如不需要 autoType):减少反序列化器缓存压力


















