Spark 内存管理之StaticMemoryManager介绍了静态资源管理器,这篇研究另外一个内存管理器UnifiedMemoryManager,统一内存管理。UnifiedMemoryManager是Spark 1.6之后默认的内存管理器。
静态资源管理器的storage、execution内存界限是固定的,那么不使用cache的情况下,storage这部分内存会存在利用不充分的问题,调优这部分内容需要开发者熟悉静态内存管理,门槛较高。鉴于此,统一内存管理器打破storage、execution的界限,storage、execution可以互相从对方借用内存。
storage、execution内存可以互相借用,如下,需要注意的是,如果execution占用了storage的内存,且storage内存也不足时,execution并不会归还这部分占用的内存,反之,storage会归还占用内存(下图来自Apache Spark 内存管理详解)。
Unified Memory Management in Spark 1.6
中详细讲解了为何选择这种策略,简单总结如下
和StaticMemoryManager相似,UnifiedMemoryManager继承MemoryManager,并重写了acquireExecutionMemory、acquireStorageMemory、acquireUnrollMemory方法,定义如下
其UML和StaticMemoryManager类似,如下
MemoryManager将内存划分为如下几部分,接下来研究静态内存管理中下面各部分占比
UnifiedMemoryManager会先预留出300M内存,剩下的记作MaxMemory,这部分内存划分为storage、execution、other等,相关代码如下
总结如下
maxmemory | total - 300M |
execution | maxmemory * 0.6 * 0.5 |
storage | maxmemory * 0.6 * 0.5 |
other | maxmemory * 0.4 + 300M |
MemoryManager在storage内存中细分了unroll,静态内存管理的实现划分了unroll这部分内存,并设置了比例。统一内存管理不再细分unroll,统一为storage。
统一内存管理最初版本other这部分内存没有固定值300M设置,而是和静态内存管理相似,设置的百分比,最初版本占25%。百分比设置在实际使用中出现了问题,若给定的内存较低时,例如1G,会导致OOM,具体讨论参考这里Make unified memory management work with small heaps,因此,other这部分内存做了修改,先划出300M内存。
spark.memory.fraction最初版本的值是0.75,很多分析统一内存管理这块的文章也是这么介绍的,同样的,在使用中发现这个值设置的偏高,导致了gc时间过长,spark 2.0版本将其调整为0.6,详细谈论参见Reduce spark.memory.fraction default to avoid overrunning old gen in JVM default config。
从上面两个例子可以看出,调整参数是内存优化的重要手段,并且要和实际的环境相结合,没有一套放之四海而皆准的准则,所以熟悉内存管理的细节显得尤为重要。
介绍了统一内存管理UnifiedMemoryManager出现的缘由,其管理的各内存的占比,以及两个重要参数的调整。
参考:
Unified Memory Management in Spark 1.6
Apache Spark 内存管理详解