<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 8.5 免清掃式位圖技術 清掃過程非常簡單,它與賦值器(用戶代碼)并發執行。 它的主要職能便是如何將一個已經從內存分配器中分配出得內存回收到內存分配器中。 ## 啟動方式 標記終止結束后,會進入`GCoff`階段,并調用`gcSweep`來并發的使后臺清掃器 Goroutine 與賦值器并發執行。 ``` func gcMarkTermination(nextTriggerRatio float64) { ... systemstack(func() { ... // 標記階段已經完成,關閉寫屏障,開始并發清掃 setGCPhase(_GCoff) gcSweep(work.mode) }) ... } ``` 其實現非常簡單,只需要將 mheap\_ 相關的標志位清零,并喚醒后臺清掃器 Goroutine 即可。 ``` //go:systemstack func gcSweep(mode gcMode) { // 此時為 GCoff 階段 ... lock(&amp;mheap_.lock) mheap_.sweepgen += 2 mheap_.sweepdone = 0 ... mheap_.pagesSwept = 0 mheap_.sweepArenas = mheap_.allArenas mheap_.reclaimIndex = 0 mheap_.reclaimCredit = 0 unlock(&amp;mheap_.lock) // 出于調試目的,用戶可以讓 sweep 過程阻塞執行,但我們并不感興趣 ... // 并發清掃(喚醒后臺 Goroutine) lock(&amp;sweep.lock) if sweep.parked { sweep.parked = false ready(sweep.g, 0, true) } unlock(&amp;sweep.lock) } ``` ## 并發清掃 清掃過程依賴下面的結構: ``` var sweep sweepdata type sweepdata struct { lock mutex g *g parked bool started bool nbgsweep uint32 npausesweep uint32 } ``` 該結構通過: 1. mutex 保證清掃過程的原子性 2. g 指針來保存所在的 Goroutine 3. started 判斷是否開始 4. nbgsweep 和 npausesweep 來統計清掃過程 當一個后臺 sweeper 從應用程序啟動時休眠后,再重新喚醒時,會進入如下循環,并一直在次循環中反復休眠與被喚醒: ``` func bgsweep(c chan int) { ... for { // 清掃 span,如果清掃了一部分 span,則記錄 bgsweep 的次數 for sweepone() != ^uintptr(0) { sweep.nbgsweep++ Gosched() } // 可搶占的釋放一些 workbufs 到堆中 for freeSomeWbufs(true) { Gosched() } // 在 mheap_ 上判斷是否完成清掃,若未完成,則繼續進行清掃 lock(&amp;sweep.lock) if !isSweepDone() { // 即 mheap_.sweepdone != 0 unlock(&amp;sweep.lock) continue } // 否則讓 Goroutine 進行 park sweep.parked = true goparkunlock(&amp;sweep.lock, waitReasonGCSweepWait, traceEvGoBlock, 1) } } ``` sweepone 從堆中清理 ``` func sweepone() uintptr { _g_ := getg() ... // 增加鎖的數量確保 Goroutine 在 sweep 中不會被搶占,進而不會將 span 留到下個 GC 產生不一致 _g_.m.locks++ if atomic.Load(&amp;mheap_.sweepdone) != 0 { _g_.m.locks-- return ^uintptr(0) } // 記錄 sweeper 的數量 atomic.Xadd(&amp;mheap_.sweepers, +1) // 尋找需要 sweep 的 span var s *mspan sg := mheap_.sweepgen for { s = mheap_.sweepSpans[1-sg/2%2].pop() if s == nil { atomic.Store(&amp;mheap_.sweepdone, 1) break } if s.state != mSpanInUse { ... continue } if s.sweepgen == sg-2 &amp;&amp; atomic.Cas(&amp;s.sweepgen, sg-2, sg-1) { break } } // sweep 找到的 span npages := ^uintptr(0) if s != nil { npages = s.npages if s.sweep(false) { // false 表示將其歸還到 heap 中 // 整個 span 都已被釋放,記錄釋放的額度,因為整個頁都能用作 span 分配了 atomic.Xadduintptr(&amp;mheap_.reclaimCredit, npages) } else { // span 還在被使用,因此返回零 // 并需要 span 移動到已經 sweep 的 in-use 列表中。 npages = 0 } } // 減少 sweeper 的數量并確保最后一個運行的 sweeper 正常標記了 mheap.sweepdone if atomic.Xadd(&amp;mheap_.sweepers, -1) == 0 &amp;&amp; atomic.Load(&amp;mheap_.sweepdone) != 0 { ... } _g_.m.locks-- return npages } ``` ``` // freeSomeWbufs 釋放一些 workbufs 回到堆中,如果需要再次調用則返回 true func freeSomeWbufs(preemptible bool) bool { const batchSize = 64 // 每個 span 需要 ~1–2 μs lock(&amp;work.wbufSpans.lock) // 如果此時在標記階段、或者 wbufSpans 為空,則不需要進行釋放 // 因為標記階段 workbufs 需要被標記,而 workbufs 為空則更不需要釋放 if gcphase != _GCoff || work.wbufSpans.free.isEmpty() { unlock(&amp;work.wbufSpans.lock) return false } systemstack(func() { gp := getg().m.curg // 清掃一批 span,64 個,大約 ~1–2 μs // 在需要被搶占時停止、在清掃完畢后停止 for i := 0; i &lt; batchSize &amp;&amp; !(preemptible &amp;&amp; gp.preempt); i++ { span := work.wbufSpans.free.first if span == nil { break } // 將 span 移除 wbufSpans 的空閑鏈表中 work.wbufSpans.free.remove(span) // 將 span 歸還到 mheap 中 mheap_.freeManual(span, &amp;memstats.gc_sys) } }) // workbufs 的空閑 span 列表尚未清空,還需要更多清掃 more := !work.wbufSpans.free.isEmpty() unlock(&amp;work.wbufSpans.lock) return more } ``` ``` //go:systemstack func (h *mheap) freeManual(s *mspan, stat *uint64) { s.needzero = 1 // span 在下次被分配走時需要對該段內存進行清零 lock(&amp;h.lock) *stat -= uint64(s.npages &lt;&lt; _PageShift) memstats.heap_sys += uint64(s.npages &lt;&lt; _PageShift) // 記錄并增加堆中的剩余空間 h.freeSpanLocked(s, false, true) // 將其釋放會堆中 unlock(&amp;h.lock) } func (h *mheap) freeSpanLocked(s *mspan, acctinuse, acctidle bool) { switch s.state { case mSpanManual: ... // panic case mSpanInUse: ... h.pagesInUse -= uint64(s.npages) // 清除 arena page bitmap 正在使用的二進制位 arena, pageIdx, pageMask := pageIndexOf(s.base()) arena.pageInUse[pageIdx] &amp;^= pageMask default: ... // panic } if acctinuse { memstats.heap_inuse -= uint64(s.npages &lt;&lt; _PageShift) } if acctidle { memstats.heap_idle += uint64(s.npages &lt;&lt; _PageShift) } s.state = mSpanFree // 與鄰居進行結合 h.coalesce(s) // 插入回 treap h.free.insert(s) } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看