<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go垃圾回收之六:掃描灰色對(duì)象

          共 1663字,需瀏覽 4分鐘

           ·

          2021-03-18 22:20

          都云作者癡,誰解其中味?

          從根對(duì)象的收集來看,會(huì)將全局變量、析構(gòu)器、所有協(xié)程的棧進(jìn)行掃描。從而標(biāo)記目前還在使用的內(nèi)存對(duì)象。 下一步是要從這些標(biāo)記為灰色的內(nèi)存對(duì)象出發(fā), 進(jìn)一步標(biāo)記整個(gè)堆內(nèi)存中活著的對(duì)象。

          在之前進(jìn)行根對(duì)象掃描的時(shí)候,會(huì)將標(biāo)記的對(duì)象放入到本地隊(duì)列中,而如果本地隊(duì)列放不下,就放入全局隊(duì)列中。這種設(shè)計(jì)最大限度的防止了使用鎖,而在本地緩存的隊(duì)列可以被邏輯處理器P無鎖訪問。

          在進(jìn)行掃描時(shí),使用相同的原理,首先消費(fèi)本地隊(duì)列中找到的標(biāo)記對(duì)象,如果本地隊(duì)列為空后,則加鎖獲取全局隊(duì)列。


          在標(biāo)記期間、會(huì)循環(huán)往復(fù)的從本地標(biāo)記隊(duì)列獲取到灰色對(duì)象,灰色對(duì)象掃描到的白色對(duì)象仍然會(huì)放入標(biāo)記隊(duì)列中,而如果掃描到已經(jīng)被標(biāo)記的對(duì)象,則進(jìn)行忽略,一直到隊(duì)列中任務(wù)為空為止。

          for !(preemptible && gp.preempt) {
          // 從本地標(biāo)記隊(duì)列中獲取對(duì)象, 獲取不到則從全局標(biāo)記隊(duì)列獲取
          b := gcw.tryGetFast()
          if b == 0 {
          // 阻塞獲取
          b = gcw.tryGet()
          }

          // 掃描獲取到的對(duì)象
          scanobject(b, gcw)
          ...
          }

          對(duì)象的掃描過程位于scanobject函數(shù)中。之前介紹過,堆上的任意一個(gè)指針能夠找到其對(duì)象所在span中的位置,并且對(duì)象有沒有被掃描,我們也可以通過gcmarkBits標(biāo)志得出。但現(xiàn)在面對(duì)的問題是需要對(duì)整個(gè)對(duì)象進(jìn)行掃描,查看對(duì)象中是否含有指針。這仍然依靠的是在分配時(shí)就記錄了對(duì)象中是否包含指針等信息。之前介紹過,heapArena 包含了 整個(gè)64M大小 的Arena元數(shù)據(jù)。

          arenas [1 << arenaL1Bits]*[1 << arenaL2Bits]*heapArena

          其中包含一個(gè)重要的字段,用位圖的形式記錄了每一個(gè)指針大小(8byte)的內(nèi)存信息。每一個(gè)指針大小的內(nèi)存都會(huì)有兩個(gè)bit分別表示是否應(yīng)該繼續(xù)掃描和是否包含指針。

          bitmap [heapArenaBitmapBytes]byte

          如下所示, bitmap代表一個(gè)位圖,其一個(gè)byte大小的空間中,對(duì)應(yīng)了虛擬內(nèi)存4個(gè)指針大小的空間。

          bitmap中前4位為掃描位,后4位為指針位。分別對(duì)應(yīng)了指定的指針大小空間是否需要繼續(xù)進(jìn)行掃描以及是否包含指針。


          例如,對(duì)于一個(gè)結(jié)構(gòu)體obj, 當(dāng)我們知道其前2個(gè)字段為指針,后面的字段以及不包含指針以后,那么后面的字段就不再需要掃描。因此,掃描位可以加速對(duì)象的掃描,避免掃描無用的字段。

          type obj struct{
          *int a
          *T b
          intc
          float d
          }

          當(dāng)發(fā)現(xiàn)需要繼續(xù)掃描并且發(fā)現(xiàn)了當(dāng)前有指針時(shí),就需要取出指針的值,并對(duì)其進(jìn)行掃描,如果發(fā)現(xiàn)引用的是堆中的白色對(duì)象(即還沒有被標(biāo)記),則標(biāo)記將該對(duì)象(表明此時(shí)已經(jīng)為灰色) 并將該對(duì)象放入本地任務(wù)隊(duì)列中。


          標(biāo)記終止階段

          當(dāng)完成并發(fā)標(biāo)記階段所有灰色對(duì)象的掃描和標(biāo)記,則進(jìn)入到標(biāo)記終止階段。標(biāo)記終止階段會(huì)再次進(jìn)入STW,標(biāo)記終止階段主要完成一些指標(biāo)例如用時(shí)的統(tǒng)計(jì)、統(tǒng)計(jì)強(qiáng)制開始GC的次數(shù)、更新下一次觸發(fā)gc需要達(dá)到的目標(biāo)、關(guān)閉寫屏障、并喚醒后臺(tái)清掃的協(xié)程,開始下一階段的清掃工作。

          在標(biāo)記終止階段重要的任務(wù)是計(jì)算下一次觸發(fā)垃圾回收時(shí)需要達(dá)到的堆目標(biāo),這叫做垃圾回收的調(diào)步算法,下一小節(jié)中將會(huì)詳細(xì)介紹。



          推薦閱讀


          福利

          我為大家整理了一份從入門到進(jìn)階的Go學(xué)習(xí)資料禮包,包含學(xué)習(xí)建議:入門看什么,進(jìn)階看什么。關(guān)注公眾號(hào) 「polarisxu」,回復(fù) ebook 獲取;還可以回復(fù)「進(jìn)群」,和數(shù)萬 Gopher 交流學(xué)習(xí)。

          瀏覽 38
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕1区 | 逼操逼网| 国产黄色电影一级片 | 男女啪啪免费网址 | 青草热|