Spring Batch任务OOM问题排查:是否为内存泄漏所致?
Spring Batch批量任务OOM问题排查
问题背景
我使用Spring Batch实现了批量任务,但执行过程中遇到OOM问题,堆内存变化如下:
同时有内存快照:
核心代码
@Tasklet class SynchronizeStudentsTasklet( private val customStudentRepository: CustomStudentRepository, private val studentClient: StudentClient, private val lectureClient: LectureClient, ) : ItemTasklet<Mono<Student>> { private val logger = getLogger() private val years = (2018..Year.now().value).toList() private var number = 100000 private var index = 0 override fun read(): Mono<Student>? = years.getOrNull(index) ?.let { year -> if (number >= 102000) { index += 1 number = 100000 } "$year${number++}" } ?.let { studentClient.getStudentByNumber(it) .flatMap { student -> Mono.zip( lectureClient.getAppliedLectureIdsByStudentNumber(it) .collectList(), lectureClient.getPreAppliedLectureIdsByStudentNumber(it) .collectList() ).map { (appliedLectureIds, preAppliedLectureIds) -> student.copy( appliedLectureIds = appliedLectureIds.toHashSet(), preAppliedLectureIds = preAppliedLectureIds.toHashSet() ) } } } override fun write(chunk: Chunk<out Mono<Student>>) { Flux.concat(chunk.items) .flatMap { customStudentRepository.upsert(it) } .doOnNext { logger.info { it } } .collectList() .block() } }
关键信息
- 批量操作采用基于chunk的批处理方式
read()方法会发起6个HTTP请求(已通过WebClient限制并发)
疑问
基于以上信息,能否确定OOM的原因是内存泄漏?
补充排查细节
- 设置
netty.leakDetection.level=advanced后,出现提示:LEAK: ByteBuf.release() was not called before garbage collection,但我们并未直接使用底层ByteBuf,仅通过WebClient发起请求。 - 确认OOM发生前执行了多次Full GC。
分析结论
目前的信息不足以直接确认OOM是内存泄漏导致,但存在指向内存泄漏的疑点,结合细节分析如下:
1. Netty ByteBuf泄漏提示的意义
虽然未直接操作ByteBuf,但WebClient基于Netty实现,该提示说明Netty的内存资源未被正确回收。可能原因包括:
- WebClient的响应处理存在异常,导致ByteBuf引用未被释放
- 依赖的
studentClient/lectureClient在封装WebClient时存在资源泄漏
2. 多次Full GC后OOM的指向
OOM前多次Full GC,说明堆内存中存在无法被回收的对象(符合内存泄漏特征),但也可能是内存使用量超过堆上限(比如单次chunk处理的数据量过大,或并发请求返回的数据未及时释放)。
3. 代码中的潜在风险
ItemTasklet泛型使用Mono<Student>,可能导致chunk中堆积大量未完成的Mono对象,这些对象持有请求上下文、ByteBuf引用等,无法被GC回收write()方法中Flux.concat(chunk.items).collectList().block()会等待所有Mono完成,若chunk size设置过大,会导致大量请求结果堆积在内存中,远超堆容量
下一步排查建议
- 分析内存快照,查看堆中占比最高的对象类型:如果是Netty的ByteBuf或WebClient上下文对象,可确认资源泄漏;如果是
Student或集合对象,可能是chunk size设置不合理 - 降低chunk size,观察OOM是否复现:若问题缓解,说明是内存过载而非泄漏;若仍出现OOM且ByteBuf泄漏提示存在,可定位到Netty资源泄漏
- 检查
studentClient和lectureClient的实现:确认WebClient的响应是否被正确消费(比如是否存在未处理的异常导致数据流中断)
内容的提问来源于stack exchange,提问作者Sangyoon Jeong
相关产品推荐
相关产品推荐

