Spark(五)内存管理

原文链接:
https://0x0fff.com/spark-memory-management/

这篇文章描述Spark的1.6版本之后的内存管理模型,其代码实现是类UnifiedMemoryManager。

长话短说,Spark的内存管理看上去是像下面这样子:
Spark(五)内存管理

根据上图,你可以看到3个主要区域:

1. 保留内存(Reserved Memory)

这个区域是系统为自己保留的,其大小是硬编码的,不可以配置。 从Spark 1.6.0开始,它的值为300MB,除非你重新编译Spark,否则你是无法改变这个值的。 注意, 这块内存虽然被称为“保留”,但它可不是为Spark用户代码保留的,即使你像把所有的java堆内存都用来保存你的数据,你也是无法使用这块保留内存的,无论你的要缓存多少数据,这块内存都只保留一些Spark的内部对象而不会缓存Spark的用户数据。 如果你不设置Spark executor至少1.5 * Reserved Memory = 450MB的堆内存, executor启动会报错: “please use larger heap size” 。

2. 用户内存(User Memory)

这是一块内存池。你可以储存你的数据结构用于RDD转换。比如,你可以重写Spark的聚合算子,通过mapPartitions转换算子来维护用于聚合的哈希表,这个聚合算子会消费用户内存。在Spark 1.6.0中, 这块内存池的大小可以这样计算:(“Java Heap” – “Reserved Memory”) * (1.0 – spark.memory.fraction), 默认等价于 (“Java Heap” – 300MB) * 0.25。 比如,一个4G的堆你会获得949MB的用户内存。 然后再次,这是一块用户内存,它取决你存储什么以及如何存储,Spark并不关心你在这个区域干什么以及你是否遵守其边界。如果你不遵守边界你会遇到OOM错误。

3. Spark内存(Spark Memory)

这是一块由Spark管理的内存池. 它的大小计算是这样的: (“Java Heap” – “Reserved Memory”) * spark.memory.fraction, 默认情况下是 (“Java Heap” – 300MB) * 0.75。比如,一个4GB的堆,这个池的大小是2847MB。这个池被一分为二:Storage Memory and Execution Memory, 它们的大小由参数spark.memory.storageFraction来控制, 默认值为0.5. 新的内存管理模式中,这两个区域的边界并非固定的,在内存面临压力时,这个边界会移动,也即是一个区域会向另外一个区域借内存。

3.1 (储存内存)Storage Memory.

这个池用于保存spark的缓存数据以及展开序列化数据需要的临时空间。另外所有的广播变量也会作为存储块保存在这里。As you may see, it does not require that enough memory for unrolled block to be available – in case there is not enough memory to fit the whole unrolled partition it would directly put it to the drive if desired persistence level allows this. 至于广播变量,所有的变量都会以MEMORY_AND_DISK级别保存在缓存中。

3.2 (执行内存)Execution Memory.

这个池保存了Spark执行时需要的内存。比如,它会被Map端用于保存shuffle的中间buffer,而且在哈希聚合阶段(hash aggregation step)它也会被用保存哈希表。如果内存不够了,这个池同样可以将部分数据spill到磁盘上,不过池里的块是不能其他线程(任务)强制收回(evicted)的。

Spark(五)内存管理

上一篇:UML建模


下一篇:Working copy 'D:\workspace\jc_gdview' locked