在 Spark 内存溢出(OutOfMemoryError) 的排查中,首先要区分是软件层配置不当还是代码逻辑导致内存占用异常。下面提供一个系统性的排查思路,帮助你判断是软件问题还是代码问题:
一、初步排查方向
| 内存是否普遍不够 | 软件配置问题 |
| 某任务、某节点频繁 OOM | 代码逻辑问题 |
| 所有任务都报相似 OOM | 软件问题可能更大 |
| Task 在运行中内存缓慢增长 | 代码中数据缓存或累积导致 |
| 提升 executor 内存后仍然溢出 | 代码逻辑问题可能更大 |
二、具体排查步骤
查看 OOM 日志信息
- 报错关键词:java.lang.OutOfMemoryError
- 看看是:
- GC overhead limit exceeded(垃圾回收过于频繁,内存紧张)
- Java heap space(堆内存不足)
- Direct buffer memory(off-heap内存问题)
这些信息能帮助我们快速定位是哪一块内存出了问题。
判断是否是 软件资源配置不足
表现:
- executor 内存(如 –executor-memory 2g)太小
- executor 数量太多,总内存超机器物理内存
- shuffle spill 频繁但磁盘也不够用
- 没有配置 spark.memory.fraction 或设置不合理(默认 0.6)
排查方式:
- 适当提高 executor memory 和 driver memory 看是否解决问题;
- 检查 spark.sql.shuffle.partitions 设置是否过大;
- 观察是否所有节点都在 OOM;
- 查看 GC 日志:是否频繁 full GC,停顿时间过长。
如果内存调高之后就不报错,说明是配置问题。
判断是否是 代码导致内存异常
典型表现:
- 某些 task 内存快速膨胀,例如:
- groupByKey() 或 reduceByKey() 输入太大;
- 使用 collect() 导致 driver 内存不足;
- 使用 rdd.cache() 缓存了大量数据;
- Dataset 操作中存在 mapPartitions 内部收集过多数据;
- 算子嵌套太深,堆栈过长导致栈溢出;
- 广播变量(broadcast)太大;
- join 前未分区或数据倾斜严重,单分区数据过大。
排查方式:
- 查看具体是哪些 stage/task 报错(Spark UI -> Executors 或 Stages);
- 查看是否只有少数 executor OOM;
- 结合源码或业务逻辑,排查数据倾斜、缓存、collect 等问题;
- 是否使用了 checkpoint?是否放在了合适位置?
三、建议工具与方法
Spark UI 重点页面
- Stages 页面:查看哪个 stage 出现问题,是否数据倾斜;
- Executors 页面:某个 executor 使用内存明显偏高;
- SQL 页面:看哪个 SQL 任务导致内存暴涨;
- Storage 页面:查看缓存的数据占用情况。
GC 日志分析
- 如果是 JVM 内存泄漏,建议打开 GC 日志分析:–conf "spark.executor.extraJavaOptions=-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc.log"
总结:如何判断
| 所有 executor 都 OOM,提升内存后恢复 | 软件配置不合理 |
| 单个 executor OOM,内存增长异常快 | 代码问题 |
| 使用 collect/cache/join/groupByKey 导致爆炸 | 代码问题 |
| executor memory 明显低于数据体量 | 软件问题 |
| 分区不合理导致单个 task 内存爆炸 | 代码问题 |




