您好,登錄后才能下訂單哦!
golang垃圾回收原理是什么,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
golang 語言設計的根本性追求就是高并發,低延遲,所以golang 的垃圾回收也是持續在優化。golang 的垃圾回收是并發垃圾回收設計,業務運行和回收器運行并發,這種設計的初衷是降低垃圾回收停頓時間。
之前提過一個例子,如果你要安全的實現回收垃圾,那么簡單的就是回收垃圾的時候,把所有的業務操作都停止,這個術語是STW(stop the world)。下面用一些術語:
下面畫了一個圖,表示了這種簡單例子的一個演進:
圖里我們看到:
這是一個顯而易見的實現和優化演進,其實再進一步,我們可以把完整的一個回收任務拆分成小粒度的,搞成一次次增量的回收,這樣單次的停頓時間就更少了。
golang 明顯不是這個(哈哈,曾經是),golang 必須要讓賦值器和回收器并發起來,不能有明顯的停頓。golang 當前的垃圾回收特點:
golang 的回收沒有混合屏障之前,一直是插入寫屏障,由于棧賦值沒有 hook 的原因,所以有 STW,混合寫屏障之后,就沒有 STW。
這里有個點要理解:STW 是全局的賦值器掛起,我們一直說 golang 消除了 STW 說的是沒有了全局性的掛起,但是局部的賦值器掛起是一直有的,包括現在也是有的。
Write 操作改變特定內存的值。改操作引發內存存儲,需要三個參數:指向源的指針、待修改域的索引、待存儲的值。寫賦值操作用偽代碼表示下:
Write(src, i, val): src[i] <- val
我們的插入寫屏障就是在這段賦值代碼中,添加一段 hook 代碼,這段 hook 代碼就是所謂的屏障代碼,由編譯器在編譯期生成。寫屏障的實現有多種,golang 使用的是 Dijkstra 算法實現:
atomic Write(src, i, ref) src[i] <- ref if isBlack(src) shade(ref)
這段偽代碼我們非常容易看懂,就是加了后面的一個判讀邏輯,如果 src 已經是黑色的,那么就把指向的新對象置灰色。
之前的文章有提到三色標記法,提到,如果要想出現對象丟失(錯誤的回收)那么必須是同時滿足兩個條件:
圖示舉例:
在這兩個條件同時出現的時候,才會出現對象被錯誤的回收。然后我們回過頭看下寫屏障的實現,就會發現,寫屏障從根本上破壞了第一個條件的出現。
加了屏障的示意圖:
插入寫屏障就是這么簡單。只要你保證時時刻刻沒有黑色對象指向白色對象的條件出現,那么回收的正確性就能保證。但是話又說回來了,這個屏障是配合賦值器回收器并發的場景才需要,如果你允許直接STW執行回收器邏輯,那就不需要這么復雜了,當然啦,這樣的話賦值器的性能肯定就不行啦。
雖然插入寫屏障能解決問題,但是 golang 針對棧上對象的賦值卻沒有捕捉(沒有生成寫屏障),原因自然是性能損耗和實現復雜度的考慮。這就開了一個例外的口子,有一些黑色的棧對象指向了白色的對象,而回收器卻無法感知到。golang 的解決方法是:最后再 STW 重新掃描一把棧。這個自然就會導致整個進程的賦值器卡頓,所以后面 golang 是引用混合寫屏障解決這個問題。
看完上述內容,你們掌握golang垃圾回收原理是什么的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。