目前Spark-2.1.0版本還保留了StaticMemoryManager靜態(tài)內存管理的邏輯,但是在代碼里默認還是使用了統(tǒng)一內存管理。兩個管理器之間選擇的控制參數是:spark.memory.useLegacyMode(設置為true時使用靜態(tài)內存管理,2.1.0版本默認為false)
UnifiedMemoryManager 的實現思路:
- 邏輯上還是分為兩塊內存,一塊用來存儲(Storage),一塊用來計算(Compute),在代碼里分別維護了一個內存池:StorageMemoryPool和ComputeMemoryPool。
- 執(zhí)行內存是指shuffle,join,aggregate,sort等計算過程使用的內存,存儲內存是指計算過程中緩存或者傳輸內部數據時使用的內存。
- 執(zhí)行內存和存儲內存共享同一塊內存空間。當各自內存池有空閑時,兩者是可以彼此借用內存空間的。執(zhí)行內存在需要時,可以強制存儲內存spill數據到磁盤,騰出內存空間給它,直到存儲內存下降到設定的閾值之下;但存儲內存沒有權限強制執(zhí)行內存將正在使用的內存借給它,官方的解釋是因為實現起來比較復雜。道理很容易想明白,對執(zhí)行過程的侵入比較容易造成task失敗。
簡單說下上面的邏輯:大家都富裕的時候,是可以彼此借用,甚至全部可用內存都歸屬一方使用;當大家資源都緊張的時候,執(zhí)行方可以強制存儲方騰出內存給他,但是有個閾值的保障,保證存儲不會把內存都貢獻出來;而執(zhí)行方不會被迫將使用的內存貢獻出來。可以理解為執(zhí)行內存有更高的優(yōu)先級。 - 統(tǒng)一內存管理的兩個參數:
spark.memory.fraction:默認0.6。(heapsize-300M)* 0.6為最大可用內存,剩下的主要存儲用戶數據和spark內部的元數據。
spark.memory.storageFraction:默認值為0.5。當存儲內存下降到最大可用內存的一半時,即使執(zhí)行內存依然需要內存,存儲也不再借出。可以理解為存儲內存的安全區(qū)域。如果該參數設置過小,數據會頻繁spill磁盤,影響任務性能