【Java 工程日志】Redisson 内存泄漏的排查方法
·
Redisson 内存泄漏排查方法
1. 确认内存泄漏现象
- 使用 JVM 监控工具(如 VisualVM、JConsole)观察堆内存变化
- 监控指标:
- 老年代(Old Gen)持续增长
- Full GC 后内存不释放
- OOM 错误日志
- Redisson 特有指标:通过
redisson.getNodesGroup().pingAll()检查连接状态
2. 堆转储分析
# 生成堆转储文件
jmap -dump:live,format=b,file=redisson_dump.hprof <pid>
- 使用 Eclipse MAT 或 JProfiler 分析:
- 查找
org.redisson开头的对象实例 - 检查
RMapCache/RBucket等缓存对象是否异常堆积 - 定位
ReferenceQueue未释放的对象
- 查找
3. 连接池泄漏检测
// 检查连接池状态
Config config = redisson.getConfig();
ConnectionManager manager = config.getConnectionManager();
System.out.println("Active connections: "
+ manager.getConnectionPool().getActiveConnections());
- 异常情况:连接数持续增长不释放
- 解决方案:检查
try-with-resources使用情况try (RLock lock = redisson.getLock("key")) { lock.lock(); // 业务逻辑 } // 自动释放
4. 监听器泄漏排查
// 事件监听器需显式移除
int listenerId = topic.addListener(MessageListener.class, (msg) -> {...});
// 业务完成后移除
topic.removeListener(listenerId);
- 常见泄漏点:
- 未移除的
RTopic消息监听器 RMap.listIterator()未关闭的迭代器RKeys.getKeysByPattern()未关闭的游标
- 未移除的
5. 缓存策略检查
- 验证缓存配置:
RMapCache<String, Object> map = redisson.getMapCache("cache"); map.put("key", value, 10, TimeUnit.MINUTES); // 必须设置TTL - 泄漏场景:
- 未设置
maxIdleTime的本地缓存 RMapCache未启用evictionPolicy
- 未设置
6. 线程泄漏检测
// 检查Redisson内部线程
Set<Thread> threads = Thread.getAllStackTraces().keySet();
threads.stream()
.filter(t -> t.getName().contains("redisson"))
.forEach(System.out::println);
- 重点关注:
redisson-netty-*线程持续增长commandExecutor线程未关闭
7. 版本与配置验证
| 配置项 | 推荐值 | 泄漏风险 |
|---|---|---|
idleTimeout |
30000 ms | 超时未释放导致堆积 |
connectionPoolSize |
64 (生产环境) | 过小引发阻塞泄漏 |
watchdogTimeout |
30000 ms | 锁续期失败导致死锁 |
8. 日志分析技巧
# 启用Redisson调试日志
-Dorg.redisson.level=DEBUG
- 关键日志模式:
DEBUG o.r.c.pool.MasterConnectionPool - free connection releasedWARN o.r.c.pool.ConnectionPool - connection not received
9. 代码审查要点
// 高危模式示例
public void leakMethod() {
RMap map = redisson.getMap("leak"); // ① 未关闭
map.put("k", new byte[1024*1024]); // ② 大对象
}
- 必须审查:
try-finally缺失的资源释放- 静态集合持有 Redisson 对象
- 未清理的
RScoredSortedSet过期元素
10. 压测验证
// 使用JMH模拟泄漏场景
@Benchmark
public void testLockLeak(Blackhole bh) {
RLock lock = redisson.getLock("bench");
lock.lock();
bh.consume(lock); // 不释放锁
}
- 监控项:
jstat -gcutil <pid> 1000jcmd <pid> VM.native_memory
终极解决方案:当定位到特定对象泄漏时,通过弱引用包装
WeakReference<RMap> weakMap = new WeakReference<>(redisson.getMap("safe"));
通过以上步骤,90%的Redisson内存泄漏问题可被定位。重点优先检查连接池、监听器和缓存配置,这些是最高频的泄漏根源。
更多推荐

所有评论(0)