排查AWS Lambda调用间内存持续攀升问题
排查Java 11 AWS Lambda调用间内存泄漏的方法
1. 生成并分析堆转储快照
- 在Lambda代码中添加堆转储逻辑,将每次调用后的堆内存快照上传到S3(需给Lambda配置S3写入权限),仅在测试阶段触发,避免影响生产性能:
import java.lang.management.ManagementFactory; import com.sun.management.HotSpotDiagnosticMXBean; import java.io.File; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.core.sync.RequestBody; // 在处理程序收尾处添加(可通过环境变量控制是否执行) if (System.getenv("ENABLE_HEAP_DUMP") != null && System.getenv("ENABLE_HEAP_DUMP").equals("true")) { HotSpotDiagnosticMXBean bean = ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); File dumpFile = new File("/tmp/heapdump_" + System.currentTimeMillis() + ".hprof"); bean.dumpHeap(dumpFile.getAbsolutePath(), true); try (S3Client s3 = S3Client.create()) { s3.putObject(b -> b.bucket("your-dump-bucket").key("lambda-heapdumps/" + dumpFile.getName()), RequestBody.fromFile(dumpFile)); } dumpFile.delete(); } - 下载多次调用后的堆转储文件,用MAT(Memory Analyzer Tool)或JProfiler打开,对比快照间的对象变化:
- 定位持续增长的对象类型,重点关注第三方库的对象实例
- 分析对象的引用链,找到持有这些对象不释放的根源(比如静态缓存、线程池、类加载器等)
2. 排查第三方库的隐式状态
- 列出所有依赖的第三方库,逐个检查:
- 查看开源库的源码或文档,确认是否存在默认启用的静态缓存、连接池或全局上下文对象(比如JSON解析库的序列化器缓存、HTTP客户端的连接池)
- 尝试在每次调用结束后调用库提供的清理方法(如
clearCache()),或避免在INIT阶段初始化库实例(改为处理程序内部创建,牺牲部分冷启动性能排查问题) - 更换库的版本测试,确认是否为特定版本的已知问题
3. 代码层面的细节检查
- 排查匿名类/内部类引用:确认是否有内部类持有了大对象(如你的HashMap)导致无法被GC回收
- 线程与ThreadLocal检查:是否存在未关闭的线程池,或ThreadLocal中存储的大对象未在调用结束后清理(第三方库也可能使用ThreadLocal缓存状态)
- 主动清理对象:在处理程序结束前将大对象(如HashMap)设置为
null,测试阶段可触发System.gc(),观察内存是否下降,判断对象是否被正常回收
4. 隔离测试场景
- 编写最小化测试Lambda:仅保留S3下载、文件解析、HashMap加载逻辑,排除业务代码干扰,验证内存是否仍增长
- 逐步添加业务逻辑或第三方依赖,定位导致内存泄漏的具体模块
5. 检查Lambda执行环境细节
- 确认
/tmp目录下的临时文件是否及时删除(未关闭的文件句柄可能间接导致内存占用) - 排查类加载器持有:Lambda的类加载器在热调用间会保留,若第三方库通过类加载器缓存对象,也可能导致内存无法释放
内容的提问来源于stack exchange,提问作者Seng Wee
相关产品推荐
相关产品推荐

