Spark的内存模型

Spark内存管理分为堆内和堆外两部分,优化了JVM的内存利用。堆内内存通过Execution和Storage进行逻辑规划,堆外内存提供更精确的管理。内存分配采用静态和统一管理两种模式,静态模式下执行和存储内存固定,统一模式下两者可动态共享。MemoryManager接口统一管理内存,ShuffleMemoryManager和BlockManager分别负责执行内存和存储内存的细节管理。当内存不足时,会触发淘汰和落盘策略。
摘要由CSDN通过智能技术生成

堆内和堆外内存

  作为一个JVM进程,Executor的内存管理建立在JVM的内存管理之上,Spark对JVM的堆内(On-heap)空间进行了更为详细的分配,以充分利用内存。同时,Spark引入了堆外(Off-heap)内存,使之可以直接在工作节点的系统内存中开辟空间,进一步优化了内存的使用。
 &emsp

堆内

  堆内内存的大小,由Spark应用程序启动时的 –executor-memoryspark.executor.memory参数配置。Executor内运行的并发任务共享JVM堆内内存,这些任务在缓存RDD和广播(Broadcast)数据时占用的内存被规划为存储(Storage)内存,而这些任务在执行Shuffle时占用的内存被规划为执行(Execution)内存,剩余的部分不做特殊规划,那些Spark内部的对象实例,或者用户定义的Spark应用程序中的对象实例,均占用剩余的空间。不同的管理模式下,这三部分占用的空间大小各不相同。
  Spark对堆内内存的管理是一种逻辑上的“规划式”的管理,因为对象实例占用内存的申请和释放都由JVM完成,Spark只能在申请后和释放前记录这些内存:
申请内存:

  • Spark在代码中new一个对象实例
  • JVM从堆内内存分配空间,创建对象并返回对象引用
  • Spark保存该对象的引用,记录该对象占用的内存

释放内存:

  • Spark记录该对象释放的内存,删除该对象的引用
  • 等待JVM的垃圾回收机制释放该对象占用的堆内内存

  对于Spark中序列化的对象,由于是字节流的形式,其占用的内存大小可直接计算,而对于非序列化的对象,其占用的内存是通过周期性地采样近似估算而得,即并不是每次新增的数据项都会计算一次占用的内存大小,这种方法可能导致某一时刻的实际内存有可能远远超出预期。此外,在被Spark标记为释放的对象实例,很有可能在实际上并没有被JVM回收,导致实际可用的内存小于Spark记录的可用内存。所以Spark并不能准确记录实际可用的堆内内存,从而也就无法完全避免内存溢出(OOM)。

堆外

  为了进一步优化内存的使用以及提高Shuffle时排序的效率,Spark引入了堆外(Off-heap)内存,使之可以直接在工作节点的系统内存中开辟空间,存储经过序列化的二进制数据。利用JDK Unsafe API,Spark可以直接操作系统堆外内存,减少了不必要的内存开销,以及频繁的GC扫描和回收,提升了处理性能。堆外内存可以被精确地申请和释放,而且序列化的数据占用的空间可以被精确计算,所以相比堆内内存来说降低了管理的难度,也降低了误差。
  在默认情况下堆外内存并不启用,可通过配置spark.memory.offHeap.enabled参数启用,并由spark.memory.offHeap.size参数设定堆外空间的大小。除了没有other空间,堆外内存与堆内内存的划分方式相同,所有运行中的并发任务共享存储内存和执行内存。

接口

  Spark为存储内存和执行内存的管理提供了统一的接口——MemoryManager,同一个Executor内的任务都调用这个接口的方法来申请或释放内存,同时在调用这些方法时都需要指定内存模式(MemoryMode),这个参数决定了是在堆内还是堆外完成这次操作。MemoryManager的具体实现上,Spark 1.6之后默认为统一管理(Unified Memory Manager)方式,1.6之前采用的静态管理(Static Memory Manager)方式仍被保留,可通过配置spark.memory.useLegacyMode参数启用。两种方式的区别在于对空间分配的方式,下面分别对这两种方式进行介绍。

内存空间分配

静态内存管理

堆内
  在静态内存管理机制下,存储内存、执行内存和其他内存三部分的大小在Spark应用程序运行期间是固定的,但用户可以在应用程序启动前进行配置,堆内内存的分配如图所示:
在这里插入图片描述

  • Execution:在执行shuffle、join、sort和aggregation时,用于缓存中间数据。通过spark.shuffle.memoryFraction进行配置,默认为0.2
  • Storage:主要用于缓存数据块以提高性能,同时也用于连续不断地广播或发送大的任务结果。通过spark.storage.memoryFraction进行配置,默认为0.6
  • Other:这部分内存用于存储运行Spark系统本身需要加载的代码与元数据,默认为0.2

可用的堆内内存的大小需要按照下面的方式计算:

可用的存储内存 = systemMaxMemory * spark.storage.memoryFraction * spark.storage.safetyFraction
可用的执行内存 = systemMaxMemory * spark.shuffle.memoryFraction * spark.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值