如有任何問題或建議,歡迎及時交流和碰撞。個人公衆號是 【腦子進煎魚了】,GitHub 地址: https://github.com/eddycjy。
你們好,我是正在學習如何蒸魚的煎魚。linux
在前面 Go1.16 特性介紹的文章中咱們有提到,從 v1.16 起,Go 在 Linux 下的默認內存管理策略會從MADV_FREE
改回 MADV_DONTNEED
策略。git
這時候可能至少分兩撥小夥伴,分別是:github
你有沒有如下的疑問,或者是否清楚:架構
MADV_FREE
是什麼?MADV_DONTNEED
是什麼?MADV_FREE
改回 MADV_DONTNEED
?在今天這篇文章中咱們都將進一步的展開和說明,讓咱們一同來了解這個改來改去的內存機制究竟是何物。微服務
在 Linux 系統中,在 Go Runtime 中經過系統調用 madvise(addr, length, advise)
方法,可以告訴內核如何處理從 addr 開始的 length 字節。工具
重點之一就是 」如何處理「,在 Linux 下 Go 語言中目前支持兩種策略,分別是:性能
Go 語言官方剛好就在 2019 年的 Go1.12 作了以下調整。學習
Go Runtime 在 Linux 上默認使用的是 MADV_DONTNEED
策略。ui
// 沒有任何奇奇怪怪的判斷 madvise(v, n, _MADV_DONTNEED)
從總體效果來看,進程 RSS 能夠降低的比較快,但從性能效率上來看差點。atom
當前 Linux 內核版本 >=4.5 時,Go Runtime 在 Linux 上默認使用了性能更爲高效的 MADV_FREE 策略。
var advise uint32 if debug.madvdontneed != 0 { advise = _MADV_DONTNEED } else { advise = atomic.Load(&adviseUnused) } if errno := madvise(v, n, int32(advise)); advise == _MADV_FREE && errno != 0 { // MADV_FREE was added in Linux 4.5. Fall back to MADV_DONTNEED if it is // not supported. atomic.Store(&adviseUnused, _MADV_DONTNEED) madvise(v, n, _MADV_DONTNEED) }
從總體效果來看,進程RSS 不會馬上降低,要等到系統有內存壓力了纔會釋放佔用,RSS 纔會降低。
故事每每不是那麼的美好,顯然在 Go1.12 起針對 madvise
的 MADV_FREE
策略的調整很是 「片面」。
結合社區裏所遇到的案例可得知,該次調整帶來了許多問題:
從社區反饋來看是問題多多,弊大於利。
官方本想着想着性能更好一些,可是在現實場景中引起了很多的新問題,甚至有提到和 Android 流程管理不兼容的狀況。
有種 「撿了芝麻,丟了西瓜」 的感受。
既然社區反饋的問題何其多,有沒有人提呢?有,超級多。
多到提出修改回 MADV_DONTNEED
的 issues 僅花了 1-2 天的時間就討論完畢。
很快得出結論且合併 CL 關閉 issues 了。
Go1.16 修改內容以下:
func parsedebugvars() { // defaults debug.cgocheck = 1 debug.invalidptr = 1 if GOOS == "linux" { debug.madvdontneed = 1 } ... }
直接指定回了 debug.madvdontneed = 1
,簡單粗暴。
在本篇文章中,咱們針對 Go 語言在 Linux 下的 madvise
方法的策略調整進行了歷史介紹和說明,同時針對其調整所帶來的的反作用及應對措施進行了一一介紹。
本次變動很好的印證了,牽一髮動全身的說法。你們在後續應用這塊時也要多加註意。
分享 Go 語言、微服務架構和奇怪的系統設計,歡迎你們關注個人公衆號和我進行交流和溝通。
最好的關係是互相成就,各位的點贊就是煎魚創做的最大動力,感謝支持。