一、静态内存管理
### --- 静态内存管理
### --- 静态内存架构
~~~ Spark 2.0 以前版本采用静态内存管理机制。存储内存、
~~~ 执行内存和其他内存的大小在 Spark 应用程序运行期间均为固定的,
~~~ 但用户可以应用程序启动前进行配置,堆内内存的分配如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/0575563ab53653cb81e520d2ee043514.png)
### --- 静态内存管理
~~~ 可用的存储内存 = systemMaxMemory * spark.storage.memoryFraction * spark.storage.safetyFraction
~~~ 可用的执行内存 = systemMaxMemory * spark.shuffle.memoryFraction *
~~~ spark.shuffle.safetyFractionsystemMaxMemory 为当前 JVM 堆内内存的大小
~~~ 这个预留的保险区域仅仅是一种逻辑上的规划,
~~~ 在具体使用时 Spark 并没有区别对待,和”其它内存”一样交给了 JVM去管理。
~~~ 堆外内存分配较为简单,只有存储内存和执行内存。
~~~ 可用的执行内存和存储内存占用的空间大小直接由参数spark.memory.storageFraction 决定。
~~~ 由于堆外内存占用的空间可以被精确计算,无需再设定保险区域。
### --- 静态内存管理
~~~ 静态内存管理机制实现起来较为简单,但如果用户不熟悉 Spark 的存储机制,
~~~ 或没有根据具体的数据规模和计算任务或做相应的配置,
~~~ 很容易造成”一半海水,一半火焰”的局面,即存储内存和执行内存中的一方剩余大量的空间,
~~~ 而另一方却早早被占满,不得不淘汰或移出旧的内容以存储新的内容。
~~~ 由于新的内存管理机制的出现,这种方式目前已经很少有开发者使用,
~~~ 出于兼容旧版本的应用程序的目的,Spark 仍然保留了它的实现。
![](https://i-blog.csdnimg.cn/blog_migrate/16416ccc37c3560df955f261d234aad7.png)
二、统一内存管理
### --- 统一内存管理
### --- 统一内存管理的堆外内存结构如下图所示:
~~~ Spark 2.0 之后引入统一内存管理机制,
~~~ 与静态内存管理的区别在于存储内存和执行内存共享同一块空间,
~~~ 可以动态占用对方的空闲区域,统一内存管理的堆内内存结构如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/9a8c1323cb02d429ce8af22bac5374a7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1117a2572f220d0a6fb86859f1a134d4.png)
### --- 其中最重要的优化在于动态占用机制,其规则如下:
### --- 统一内存管理执行过程
~~~ 设定基本的存储内存和执行内存区域(spark.storage.storageFraction 参数),
~~~ 该设定确定了双方各自拥有的空间的范围
~~~ 双方的空间都不足时,则存储到硬盘;若己方空间不足而对方空余时,
~~~ 可借用对方的空间;(存储空间不足指不足以放下一个完整的 Block)
~~~ 执行内存的空间被对方占用后,可让对方将占用的部分转存到硬盘,然后”归还”借用的空间
~~~ 存储内存的空间被对方占用后,无法让对方”归还”,
~~~ 因为需要考虑 Shuffle 过程中的很多因素,实现起来较为复杂
![](https://i-blog.csdnimg.cn/blog_migrate/2d659467b041a4e5c8326eb8a4a1e29d.png)
### --- 统一内存管理执行过程
~~~ 在执行过程中:执行内存的优先级 > 存储内存的优先级(理解)
~~~ 凭借统一内存管理机制,Spark 在一定程度上提高了堆内和堆外内存资源的利用率,
~~~ 降低了开发者维护 Spark 内存的难度,但并不意味着开发者可以高枕无忧。
~~~ 如果存储内存的空间太大或者说缓存的数据过多,反而会导致频繁的全量垃圾回收,
~~~ 降低任务执行时的性能,因为缓存的 RDD 数据通常都是长期驻留内存的。
~~~ 所以要想充分发挥 Spark 的性能,
~~~ 需要开发者进一步了解存储内存和执行内存各自的管理方式和实现原理。