Spark读取Excel报GC overhead limit exceeded错误原因及内存配置咨询
问题核心原因分析
- local模式配置失效:你使用
local[*]模式运行Spark作业,该模式下Driver和Executor运行在同一个JVM进程中,代码中设置的spark.executor.memory完全不生效,仅Driver内存配置会生效。且在代码中初始化SparkConf后再设置Driver内存属于无效操作,因为JVM启动时内存已完成分配,后续修改参数不会生效。 - spark-excel解析特性:你使用的crealytics spark-excel组件默认会将完整Excel文件加载到Driver端内存做全量解析,不会做分布式分片读取,即使文件只有8MB,如果文件内存在大量合并单元格、隐藏列、复杂格式或元数据,解析过程也会占用数倍于文件大小的内存。
- GC效率超限:报错
java.lang.OutOfMemoryError: GC overhead limit exceeded并非内存完全耗尽,而是JVM花费了98%以上的CPU时间执行GC操作,但仅回收了不到2%的堆内存,说明内存中存在大量短生命周期对象频繁触发GC,没有足够内存供正常计算使用。 - 版本适配问题:Spark 2.4.4官方默认适配Scala 2.11版本,你使用Scala 2.12.12存在版本不兼容问题,会引发不必要的内存泄漏、反射调用开销过高问题,进一步加剧内存占用。
解决方法
1. 本地运行模式(local[*])内存调整
- 不要在代码中设置Driver内存,打开IntelliJ对应作业的运行配置,在VM options栏添加以下参数:
-Xmx8g -Xms4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 # 临时关闭GC超限检查,仅用于排查,不建议长期开启 # -XX:-UseGCOverheadLimit
- 移除代码中无效的
spark.executor.memory配置,该参数在local模式下无任何作用。
2. Excel读取参数优化
调整spark-excel读取配置,降低内存占用:
val df = spark.read .format("com.crealytics.spark.excel") .option("header", "true") // 分批解析,限制内存中最多存放的行数,避免全量加载 .option("maxRowsInMemory", 10000) // 提前指定列Schema,避免全表扫描做类型推断 // .schema(customSchema) // 指定读取的sheet,避免扫描所有sheet // .option("sheetName", "Sheet1") .load("data/12file.xlsx")
3. 版本适配修正
要么将Scala版本降级到2.11.x适配Spark 2.4.4,要么将Spark版本升级到3.x系列适配Scala 2.12.x,消除版本不兼容带来的内存泄漏问题。
4. 集群模式运行时Executor内存调整
如果后续提交到YARN/K8s集群运行,按以下规则配置Executor内存:
- 基础内存设置:根据作业数据量设置
spark.executor.memory,常规批处理作业建议设置8g~16g,避免内存过小频繁GC,也避免内存过大GC停顿过长。 - 内存比例调整:设置
spark.memory.fraction=0.7~0.8,调高Spark计算可用的堆内存比例,降低存储内存占比。 - 堆外内存配置:设置
spark.executor.memoryOverhead=2g~4g,预留足够堆外内存处理IO、序列化等操作,避免堆外内存溢出。
内容的提问来源于stack exchange,提问作者Sarvesh Singh
相关产品推荐
相关产品推荐

