强引用缓存导致内存耗尽,引发频繁full gc与stw延长,进而造成线程调度失衡、看似锁饥饿;本质是堆内存被强引用对象持续占满,需通过jstat/jmap定位高占用对象及gc roots路径,并结合关闭缓存、限流、弱/软引用等手段治理。

这不是典型的“锁饥饿”,而是强引用缓存导致的内存型资源耗尽,间接引发线程调度失衡。所谓“系统级锁饥饿”在这里实际表现为:大量线程因等待数据库连接、线程池任务队列、或同步块而长期阻塞(WAITING / TIMED_WAITING),表面像饥饿,根源却是堆内存被缓存对象持续占满,触发频繁 Full GC,使 JVM STW 时间剧增、线程几乎无法调度执行。
确认是否为强引用缓存引发的内存挤压
先排除传统锁竞争问题,聚焦内存侧证据:
- 用
jstat -gc <pid></pid>观察:Old Gen 使用率持续 >95%,且FGC次数陡增、FGCT时间不断拉长(单次超500ms) - 用
jmap -dump:format=b,file=heap.hprof <pid></pid>抓取堆快照,重点检查:- 是否存在大量重复结构的对象(如
DruidStatData、SQLUtils.ParsedSql、自定义CacheEntry等) - 这些对象是否通过静态 Map、ConcurrentHashMap 或单例缓存管理器持有强引用(查看其 GC Roots 路径)
- 字符串类(
java.lang.String)实例数异常高,且多数被缓存框架内部结构(如 SQL 模板、Key 拼接结果)直接引用
- 是否存在大量重复结构的对象(如
- 检查应用日志中是否有
java.lang.OutOfMemoryError: Java heap space或GC overhead limit exceeded,即使未 OOM,GC 压力已实质影响线程活性
定位具体缓存框架与错误用法
常见强引用缓存误用模式:
-
Druid 1.1.22+ 的 SQL 统计缓存:开启
stat-view-servlet或useGlobalDataSourceStat=true后,sqlStatMap无上限缓存所有动态拼接 SQL(如带用户 ID、时间戳的查询),每个 SQL 字符串被强引用,永不释放 -
Guava Cache 未设 maximumSize / expireAfterWrite:使用
CacheBuilder.newBuilder().build()默认无限制,缓存条目无限增长 -
自研 HashMap/ConcurrentHashMap 缓存 + 静态引用:例如
private static final Map<string object> GLOBAL_CACHE = new ConcurrentHashMap();</string>,且未做容量控制或过期清理 -
MyBatis 二级缓存开启但未配置 eviction 策略:尤其搭配
PERPETUAL驱逐策略时,缓存永驻堆中
快速缓解与验证手段
不重启即可初步验证问题归属:
- 临时关闭可疑缓存功能:
- Druid:设置
druid.stat.mergeSql=false、druid.filter.stat.enabled=false - Guava:在构建时强制加入
.maximumSize(1000).expireAfterWrite(10, TimeUnit.MINUTES) - MyBatis:在 mapper XML 中添加
<cache eviction="LRU" size="1024"></cache>
- Druid:设置
- 用
jcmd <pid> VM.native_memory summary</pid>对比开启/关闭前后 internal 区变化(反映 JIT、元空间等间接压力) - 观察 GC 日志:Full GC 频次下降、STW 时间缩短后,线程阻塞状态(
jstack <pid></pid>中 WAITING 线程数明显减少),即证实为内存挤压导致的“伪饥饿”
长期治理关键点
避免再次陷入同类陷阱:
- 所有缓存必须明确生命周期:设定大小上限、写入过期、访问过期三者至少满足其一
- 敏感缓存(如 SQL、用户会话)优先使用弱引用(
WeakReference)或软引用(SoftReference)包装值,配合 ReferenceQueue 清理 - 生产环境禁用 Druid、HikariCP 等连接池的全量 SQL 统计;如需监控,改用采样模式(如 Druid 的
connectionProperties=druid.stat.samplingRate=0.01) - 在 CI/CD 流水线中加入内存扫描检查:对代码扫描
static.*Map、new CacheBuilder、@Cacheable无参数等高风险模式










