1.6版本内存模型
1.6之前的版本是一个静态的内存模型,executor中分成三个部分,一部分是Execution区域,一部分是Storage内存区域,还有是预留的其他给spark的内部使用的区域,在spark的configuration中默认的有以下参数控制。
spark.storage.memoryFraction: 默认0.6
spark.shuffle.memoryFraction: 默认0.2
Storage内存模型这一部分主要是处理cache操作和广播变量这些。
Execution就是执行map,join,reduce等这些任务的。
那么我们为啥要知道这个呢?就是我们想一个事情,如果假如我们的代码中有shuffle操作,我们都是shuffle,而且其中有一个key的值非常大,我们就需要Execution的内存要大,但是不要意思,只给他分配了0.2,这个时候会出现什么问题呢?毫无疑问,在数据量大于0.2的Execution的时候,一定会出现内存溢出的问题。你可能想,storage内存那么大,我能不能用一些呢?不好意思,不可以,这就是静态模型,也就是静态模型中,storage的内存部分和Execution内存部分不能相互借用,所以这里就是优化点,也就是假如我们运行的代码在spark1.6版本之前的话,我们运行之前就要先想好到底是storage需要的多还是Execution多,我们手动的指定,读到这里,你是不是觉得非常不方便?是的,非常麻烦。于是我们就引入我们的统一内存模型
2.0版本统一内存模型
统一静态模型,系统预留300M,然后把剩余内存整体划分为两个部分,由spark.memory.fraction这个指定默认值是0.6,另外一部分是0.4,然后spark.memory.fraction这部分又划分两个小部分,这两个小部分整体占用0.6,这两份其实就是storage内存和execution内存。上面我们说静态模型的时候,提到storage和execution不能互相借用,但是在这里他们可以相互借用
垃圾回收优化
如果发现,在task执行期间,大量full gc 发生了 ,那么说明,年轻代的Survivor区域,给的空间不够大,此时可以执行一些操作来优化垃圾回收行为:
1.包括降低spark.storage.memoryFraction的比例,给年轻代更多的空间,来存放短时间存活的对象;
2.给Eden 区域分配更大的空间,使用-Xmm即可 ,通常建议给Eden 区域,预计大小的4/3;
3.如果使用的是HDFS文件,那么很好估计Eden区域大小,如果executor有4个task.然后每个hdfs压缩块 解压缩后大小是3倍,此外每个hdfs块的大小是64m,那么Eden区域的预计大小就是:4364MB.