昨天学习了 Spark 堆外内存和堆内内存的概念。没看过的可以看前面的文章。
今天学习内存空间分配。
1.静态内存管理
早期采用静态管理,存储内存、执行内存和其他内存的大小在 Spark 应用程序运行期间均为固定的,但用户可以应用程序启动前进行配置。
问题:如果用户不熟悉 Spark 的存储机制,或没有根据具体的数据规模和计算任务或做相应的配置,很容易造成存储内存和执行内存中的一方剩余大量的空间,而另一方却早早被占满,不得不淘汰或移出旧的内容以存储新的内容。
2.统一内存管理
Spark 1.6 之后引入的统一内存管理机制,与静态内存管理的区别在于存储内存和执行内存共享同一块空间,可以动态占用对方的空闲区域。
统一内存管理的堆内内存结构如图所示:
统一内存管理的堆外内存结构如下图所示:
其中最重要的优化在于动态占用机制,其规则如下:
- 设定基本的存储内存和执行内存区域(
spark.storage.storageFraction
参数),该设定确定了双方各自拥有的空间的范围; - 双方的空间都不足时,则存储到硬盘;若己方空间不足而对方空余时,可借用对方的空间(存储空间不足是指不足以放下一个完整的Block);
- 执行内存的空间被对方占用后,可让对方将占用的部分转存到硬盘,然后”归还”借用的空间;
- 存储内存的空间被对方占用后,无法让对方”归还”,因为需要考虑 Shuffle 过程中的很多因素,实现起来较为复杂。
3.总结
- 优点:凭借统一内存管理机制,Spark 在一定程度上提高了堆内和堆外内存资源的利用率,降低了开发者维护 Spark 内存的难度;
- 不足:如果存储内存的空间太大或者说缓存的数据过多,反而会导致频繁的全量垃圾回收,降低任务执行时的性能,因为缓存的RDD数据通常都是长期驻留内存的。
因此所以要想充分发挥Spark的性能,需要开发者进一步了解存储内存和执行内存各自的管理方式和实现原理。明天对这一部分进行介绍。