Spark 核心之 Spark 内存管理深度剖析

摘要:Spark 内存管理是性能调优的核心战场------理解 UnifiedMemoryManager 的 Execution/Storage 动态借用机制、Tungsten 页式分配、Off-Heap 与 On-Heap 的权衡、以及 acquire → evict → spill 的分配溢出流程,是避免 OOM、提升 Shuffle 效率的关键。本文从 JVM Heap 分区架构、Unified vs Static 对比、内存分配失败处理链、Tungsten MemoryAllocator、堆外内存与常见 OOM 调优六个维度,配合 2 张原创架构图 + 源码追踪,彻底拆解 Spark 内存管理全貌。

关键词:UnifiedMemoryManager, Execution Memory, Storage Memory, Tungsten, Off-Heap, Eviction, Spill, OOM 调优


一、开篇:你的 Executor 内存花在哪了?

一个 spark.executor.memory=4g 的 Executor,实际可用内存远小于 4GB。Spark 将 JVM Heap 划分为三层:

yaml 复制代码
4GB Executor Heap 默认划分
├── Reserved Memory:      300MB  (固定,不可调)
├── User Memory:          1.48GB (1 - 0.6) × (4G - 300M)
│    └── 存放 RDD 闭包引用、用户自定义数据结构
└── Spark Memory (统一池): 2.22GB  0.6 × (4G - 300M)
     ├── Storage Memory:   1.11GB (默认 50%)
     └── Execution Memory: 1.11GB (默认 50%)
        两者可动态互借!

二、UnifiedMemoryManager 架构全景

2.1 三层 Heap 架构

scala 复制代码
// UnifiedMemoryManager.getMaxExecutionMemory()
val maxMemory = systemMemory - reservedMemory                // 可用总内存
val sparkMemory = maxMemory * conf.get(MEMORY_FRACTION)      // Spark 池
val storageMemory = sparkMemory * conf.get(STORAGE_FRACTION) // Storage 初始占比
val executionMemory = sparkMemory - storageMemory            // Execution 初始占比

// 动态借用: Execution 可借用 Storage 空闲部分
// Storage 也可借用 Execution 空闲部分(但 Execution 需要时可踢回)

2.2 动态借用规则

yaml 复制代码
Execution 借用 Storage:
  Storage 有闲置 → Execution 直接拿走 → 不归还

Storage 借用 Execution:
  Execution 有闲置 → Storage 暂时使用
  → Execution 需要时会触发 Eviction → 淘汰 Storage Block

核心: Execution 优先级高于 Storage
  acquireExecutionMemory() → 先用自己的 pool → 不够→借Storage→还不够→spill磁盘

三、内存分配与溢出流程

3.1 三步处理

scss 复制代码
MemoryConsumer.acquireMemory(requiredSize):
  ① 检查 Execution Pool 余额 → 够用直接分配
  ② 余额不足 → evictBlocksToFreeSpace(required)
     - 从 Storage Pool 淘汰 RDD Block 缓存
  ③ 仍不够 → MemoryConsumer.spill() 自身溢写磁盘
     - 释放内存后重试 acquire

3.2 核心源码

scala 复制代码
// UnifiedMemoryManager.acquireExecutionMemory()
override def acquireExecutionMemory(numBytes: Long, ...): Long = {
  synchronized {
    // 尝试从 Storage 借: 淘汰 Storage Block 释放空间
    val memoryReclaimableFromStorage = math.max(
      storagePool.memoryFree,
      storagePool.poolSize - storageRegionSize)
    val spaceReclaimed = storagePool.evictBlocksToFreeSpace(...)
    // 更新可用总量
    val maxToGrant = math.min(numBytes,
      math.max(0, maxExecutionMemory - executionPool.poolSize))
    executionPool.incrementPoolSize(maxToGrant)
    maxToGrant
  }
}

四、Tungsten 页式内存管理

scala 复制代码
// Tungsten 内存模型
MemoryAllocator (Heap / Unsafe)
  → allocate(size) → MemoryBlock(obj/offset, length)

TaskMemoryManager
  → allocatePage(size) → 64-bit 逻辑地址
  → pageTable 逻辑地址到物理地址映射
  → 高 13bit: pageNumber (最多 8192 页)
  → 低 51bit: offsetInPage

优势:
├── 不受 GC 影响(Unsafe 模式)
├── 精确控制内存生命周期
├── 64 位单一地址空间
└── 页式管理减少碎片
properties 复制代码
spark.memory.offHeap.enabled=true    # 开启堆外内存
spark.memory.offHeap.size=2g         # 堆外大小
# 堆外内存独立于 JVM Heap,不受 GC 影响

五、Unified vs Static --- 为什么必须 Unified?

makefile 复制代码
StaticMemoryManager (Legacy) 问题:
  Execution 池 + Storage 池 = 固定分割,互不借用
  → Execution 满而 Storage 空 → 直接 OOM

UnifiedMemoryManager:
  统一池 + 动态借用 → 利用率最大化
  Spark 1.6+ 默认 → 生产环境唯一推荐

六、OOM 场景与调优

常见 OOM

yaml 复制代码
① User Memory OOM:  闭包引用了大对象 → 广播变量解决
② Execution Memory OOM: Shuffle 数据量过大 → 增大 fraction
③ Storage Memory OOM:  缓存过多 → 减少缓存或用 DISK_ONLY
④ Off-Heap OOM:  spark.memory.offHeap.size 不足 → 增大

调优公式

scss 复制代码
Execution 可用内存 (最小保证)
= (Heap - 300MB) × spark.memory.fraction × (1 - spark.memory.storageFraction)

调优策略:
① Shuffle 密集型: 增大 fraction (0.6→0.75) 或 减少 storageFraction (0.5→0.3)
② Cache 密集型:  增大 storageFraction (0.5→0.7)
③ GC 压力大:      开启堆外内存
④ User Memory 不足: 增大 Heap 或 减少闭包变量大小

七、总结

  1. 三层 Heap:Reserved(300M) + User((1-f)×Heap) + Spark(f×(Heap-300M))。Execution/Storage 动态借用。

  2. 分配失败链:Execution Pool → 借 Storage(evict) → 自身 spill 磁盘。Execution 优先级 > Storage。

  3. 调优关键:fraction 控 Spark 池大小、storageFraction 控 Storage 占比、offHeap 解 GC 之困。


作者 :starzy

博客blog.starzy.cn

GitHubstarzy1990.github.io

专注 AI Agent · LangGraph · RAG · 大数据架构 · 数据工程实践

相关推荐
跨境小彭2 小时前
Temu运营优化方案:活动库存自动化管控,解决断流、超卖与权重下跌问题
大数据·运维·人工智能·自动化·跨境电商·temu·temu电商运营
风途科技~2 小时前
峰值日照时数精准测,这款光伏电站环境监测仪器助力电站发电量评估
大数据·人工智能
漫谈数据智理2 小时前
IDS-RAM 如何支撑数据空间走向可
大数据·运维·微服务
江苏汉软3 小时前
mes现场管理系统
大数据
tanglinS3 小时前
工业陶瓷在半导体设备里都用哪里?氮化铝基板与氮化硅结构件的静电无尘角色
大数据·运维·人工智能·自动化·材质
慧新软件3 小时前
Google算法更新后,外贸SEO优化策略如何调整
大数据
xushichang123_4 小时前
如何观看 2026 亚马逊云科技中国峰会全场主题演讲与技术分论坛内容?
大数据·人工智能
招财小梗4 小时前
AI矩阵获客,品牌连锁落地有啥方案?
大数据·人工智能·矩阵
黎子越4 小时前
大模型基础名词概念
大数据