大數據計算框架Spark之內存模型
Executor 端的內存模型,包括堆內內存(On-heap Memory)和堆外內存(Off-heap Memory)。

存管理接口(MemoryManager )
Spark 為Execution 內存和Storage 內存的管理提供了統一的接:MemoryManager。
MemoryManager 的具體實現上,Spark 1.6 之后默認為統一管理(Unified Memory Manager)方式,1.6 之前采用的靜態管理(Static Memory Manager)方式仍被保留,可通過配置 spark.memory.useLegacyMode 參數啟用。
1靜態內存管理(Static Memory Manager)
堆內空間管理
存儲內存、執行內存和其他內存的大小在 Spark 應用程序運行期間均為固定的,但可以在應用程序啟動前進行配置。
可用的Execution 內存和 可用的Storage 內存計算公式:
可用的Execution 內存 = systemMaxMemory * spark.shuffle.memoryFraction * spark.shuffle.safetyFraction
可用的Storage 內存 = systemMaxMemory * spark.storage.memoryFraction * spark.storage.safetyFraction
systemMaxMemory 取決于當前 JVM 堆內內存的大小,公式中的兩個 safetyFraction 參數,其意義在于在邏輯上預留出一塊保險區域,降低因實際內存超出當前預設范圍而導致 OOM 的風險。這塊邏輯上預留的區域同樣由JVM管理。

圖靜態內存管理-堆內內存的分配
堆外空間管理
堆外只有Execution 內存和Storage 內存,他們的大小由spark.memory.storageFraction這個參數決定。由于堆外內存占用的空間可以被精確計算,所以無需再設定保險區域

靜態內存管理-堆外內存的分配
2統一內存管理
Spark 1.6 之后引入的統一內存管理機制,與靜態內存管理的區別在于Storage 內存和Execution 內存共享同一塊空間,可以動態占用對方的空閑區域。
堆內內存(On-heap Memory)
堆內內存區域大致可以分為以下四類:
1)Execution 內存:主要用于存放 Shuffle、Join、Sort、Aggregation 等計算過程中的臨時數據
2)Storage 內存:主要用于緩存和傳播內部數據
3)Other:用戶數據結構、Spark內部元數據。
4)預留內存(Reserved Memory):系統預留內存。默認是300MB。

堆內存(Off-heap Memory)
Spark 1.6 開始引入了Off-heap memory(詳見SPARK-11389)。這種模式不在 JVM 內申請內存,而是調用 Java unsafe API (如 C 語言里面的 malloc())直接向操作系統申請內存,JVM不管理這部分內存,所以可以避免頻繁的 GC,但要自己編寫內存申請和釋放的邏輯。
堆外內存分為兩類:Execution 內存和 Storage 內存。
默認情況下堆外內存不啟用,可以通過配置spark.memory.offHeap.enabled 參數啟用,通過配置spark.memory.offHeap.size 參數設定堆外內存空間的大小。
如果堆外內存被啟用,那么 Executor 內將同時存在堆內和堆外內存,Executor 中的 Execution 內存是堆內的 Execution 內存和堆外的 Execution 內存之和,同理,Storage 內存也一樣。

說明
maxOffHeapMemory=spark.memory.offHeap.size
Execution 內存和 Storage 內存動態調整
1)設定基本的Storage 內存和Execution 內存區域(通過spark.storage.storageFraction配置比例,默認是0.5,即各占一半)
2)Storage 內存和Execution 內存都不足時,則存儲到硬盤;若己方空間不足而對方空余時,可借用對方的空間;(存儲空間不足是指不足以放下一個完整的 Block)
3)Execution 內存空間被對方占用后,可讓對方將占用的部分轉存到硬盤,然后"歸還"借用的空間
4)Storage 內存空間被對方占用后,無法讓對方"歸還",因為實現起來較為復雜。

動態整