共計 2132 個字符,預計需要花費 6 分鐘才能閱讀完成。
這篇文章跟大家分析一下“golang 垃圾回收該如何分析”。內容詳細易懂,對“golang 垃圾回收該如何分析”感興趣的朋友可以跟著丸趣 TV 小編的思路慢慢深入來閱讀一下,希望閱讀后能夠對大家有所幫助。下面跟著丸趣 TV 小編一起深入學習“golang 垃圾回收該如何分析”的知識吧。
概述
現代編程語言一般都有垃圾回收功能。這個能極大的減輕程序員的負擔,并且減少大部分場景的問題。要知道,c 語言里面最常見的就是踩內存,內存泄漏,野指針等問題。golang 作為一個新新語言,自然垃圾回收功能少不了的。當前 golang 的垃圾回收基于的理論是三色標記法,并且通過合理的使用內存屏障技術,把垃圾回收的 stw 幾乎消滅(旁白:這個正確的理解,并不是沒有 stw,只是非常非常短了)。
GC RC
首先,內存稍高級的管理有兩個方式,了解兩個名詞:
GC:垃圾回收管理內存的方式 RC:引用計數管理內存的方式
由于 c 語言自身設計的問題,無法實現 GC,所以 c 程序怎么管理內存呢?引用計數就是最常用的稍高級的管理方式。引用計數怎么用?常用姿勢如下:
使用前,為了保護對象不被銷毀,計數 + 1 使用完后,計數 -1,計數減到 0 之后,就可以安全銷毀了
obj_ref(obj);{ do_something ; }obj_unref(obj);
引用計數 RC 的使用看上面非常簡單,但其實是非常有講究的,這里不深入了。此處還是由 golang 的垃圾回收展開。
golang 的垃圾回收我們經常聽到三色標記法,三色指的是白色,灰色,黑色,分別表示三種狀態,至于三色標記法的理論此處不表,我們從簡單的理解切入。
垃圾回收的由來
首先,我們思考下一個不需要思考的問題:垃圾回收是做什么的?golang 為什么需要垃圾回收?
c 程序跑起來是需要內存的,棧內存由編譯器來管理,堆內存由程序員來管理,這個就是 c 程序出內存問題的源頭,程序員是人,是人就可能出錯,各種編程人員的素質也是參差不齊,實際場景也是各種復雜的情況交織。
所以,我們回歸本源問題,我們本質上只是想要一個內存而已,管理它只是迫不得已。內存用完了,程序員最好也不管。程序員只管用,不管回收。這個就會垃圾回收的由來。
逃逸分析的由來
我們再進一步,c 程序還需要程序員自己決定從棧上分配內存,還是堆上分配內存?
那么這個事情是程序員必須要做的嗎?并不是,本質上程序只是需要一個對象,決定這個事情也是迫不得已。
golang 解決這個事情,就是對應的”逃逸分析“。逃逸分析解決一個問題,在保證 golang 程序正確性的前提下,在編譯階段決定對象的分配位置,棧上?堆上?
垃圾回收,怎么實現?
底線:golang 只需要保證一個點,回收的一定是不用的垃圾,那么就不會出功能性問題,回收的慢點一定程度都 ok 的。
什么樣的是垃圾?
怎么保證回收的一定是垃圾?首先看張圖:
先說結論:
圖上黃色的就是垃圾,這個從圖里一眼就能看出來。沒人用它呀,可不就是垃圾嘛 怎么把垃圾找出來?
現在關鍵的問題是:這個黃色塊怎么找出來的?
換個說法:你把在用的找明白,剩下的就是沒在用的垃圾了。什么是在用的呢?從所有的根出發,只要是引用覆蓋到的,就認為在用。
方法:從根處掃描,把所有的根掃描完,每個根掃描到底。按照之前的三色標記來說,掃描完了的是黑色,正在掃描的是灰色的,沒掃描的是白色的。根掃描完了,那么最后只會剩下兩種顏色的,黑色,白色。白色就是沒用的垃圾,這種清理掉就沒事。
問兩個問題:
那么根是什么?回收的內存是哪里的內存?
答案:
棧是根,是掃描的起點,還有一些全局變量也是根,是起點所謂垃圾只對于堆上內存來說,棧上內存是編譯器管理的,堆上內存是業務分配,垃圾回收器回收
下面說另一個關鍵點:怎么掃描是安全的?
最簡單的思路,我讓世界都停止下來(stw),誰都別動,等我把垃圾找出來,你再運行你的程序吧。這就安全了吧。
還真別說,golang 1.0 就是這么干的。這種實現非常簡單也易于理解,但是無法適用于生產環境,你一停整個程序,就要暫停業務,一停就幾秒,所以前期的 golang 根本就不能用呀。
所以呀,為了能夠在線上生產場景使用,而不僅僅是個玩具,那么必須要做到垃圾回收不影響業務代碼的運行才行。也就是并發嘍(旁白:不并發也行,只要你能想到好辦法,能做到:能回收垃圾,又不影響業務)?簡單的并發就有要考慮的問題了,先說不安全的例子(掃描和業務并發):
初始場景:
業務和掃描并發:
最后結果:
這白色的就是要被回收的,但我們一看就知道,有一個白色的被引用了,回收就野指針了,被回收掉就垮掉了。
內存屏障
怎么解決這個問題?接下來就是內存屏障出場了。golang 內存屏障也有一個演進過程:
插入寫屏障混合寫屏障(插入寫屏障 + 刪除寫屏障)
先說屏障的本質:
內存屏障只是對應一段特殊的代碼內存屏障這段代碼在編譯期間生成內存屏障本質上在運行期間攔截內存寫操作,相當于一個 hook 調用
屏障的作用:
通過 hook 內存的寫操作時機,阻止一些事情的發生,或者說做好一些標記工作,從而保證垃圾回收的正確性
關于 golang 垃圾回收該如何分析就分享到這里啦,希望上述內容能夠讓大家有所提升。如果想要學習更多知識,請大家多多留意丸趣 TV 小編的更新。謝謝大家關注一下丸趣 TV 網站!