You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spark 3.2读取JSON时Driver GC溢出,Spark 2.3无此问题

问题:Spark 3.2加载JSON DataFrame时Driver内存溢出,Spark 2.3无此问题

运行脚本

val files = fs.globStatus(path).filter{_.isDirectory == false} // 50个文件,每个约100MB
val fileMap = scala.collection.mutable.Map.empty[String, DataFrame] 
files.par.foreach {f =>
  val filename = f.getPath.getName.toString
  val df = spark.read.option("mode", "DROPMALFORMED").json(f.getPath.toString)
  fileMap.update(filename , df)
}

问题现象

使用4GB Driver内存运行Spark 3.2时,出现GC Overhead错误;但相同参数下Spark 2.3可正常完成任务——Spark 2.3的JVM内存占用约2.3GB,Spark 3.2则超过4GB并崩溃。

两种场景下所有参数一致,JSON文件包含嵌套结构,约有800列。

疑问

  1. 代码未调用任何Action,仅存储DataFrame引用,为何Driver仍消耗大量内存?
  2. 两个Spark版本行为差异的原因是什么?

解答

1. 未触发Action仍消耗Driver内存的原因

Spark的DataFrame并非单纯的引用,它包含逻辑执行计划和完整的Schema元数据。读取JSON文件时,Spark必须先完成Schema推断:即便没有触发Action,这个推断过程会在Driver端执行,需要将包含800列的嵌套Schema完整加载到内存中。

另外,代码中使用了Scala的par.foreach并行集合,这会在Driver端启动多线程处理每个文件的Schema推断,每个线程生成的DataFrame元数据都会驻留在Driver堆内存中,大量元数据累积后就会占用可观的内存空间。

2. Spark 2.3与3.2的行为差异原因

核心差异来自Schema推断、元数据存储和内存管理的版本迭代:

  • Schema推断逻辑增强:Spark 3.x对JSON Schema的推断更细致,比如精准区分数值类型(long/int)、保留嵌套结构的更多细节,导致Schema元数据的体积比Spark 2.3显著增大。
  • 元数据存储结构重构:Spark 3.x对Catalog和元数据管理做了重构,DataFrame的执行计划、元数据对象的内存占用比2.3版本更高,对于大列数的Schema,内存增幅会被放大。
  • Driver端内存管理差异:Spark 3.x的Driver内存模型更严格,加上Scala并行集合的线程在Driver端运行时,内存分配效率不如2.3版本,同时3.x对对象引用的追踪更细致,GC压力剧增,最终触发GC Overhead错误。

临时解决方案

  • 替换Scala并行集合:改用Spark分布式API处理文件读取(比如spark.read.json(files.map(_.getPath.toString))),或者分批次处理,降低Driver端并发压力。
  • 手动指定Schema:提前编写StructType定义JSON结构,跳过自动Schema推断,大幅减少Driver内存占用。
  • 调整Driver配置:增加Driver内存,或改用G1GC等更高效的垃圾回收器,缓解GC压力。

内容的提问来源于stack exchange,提问作者ASR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 11:23:02