清扫

  1. func gcSweep(mode gcMode) {
  2. ...
  3. //阻塞式
  4. if !_ConcurrentSweep || mode == gcForceBlockMode {
  5. // Special case synchronous sweep.
  6. ...
  7. // Sweep all spans eagerly.
  8. for sweepone() != ^uintptr(0) {
  9. sweep.npausesweep++
  10. }
  11. // Do an additional mProf_GC, because all 'free' events are now real as well.
  12. mProf_GC()
  13. mProf_GC()
  14. return
  15. }
  16. // 并行式
  17. // Background sweep.
  18. lock(&sweep.lock)
  19. if sweep.parked {
  20. sweep.parked = false
  21. ready(sweep.g, 0, true)
  22. }
  23. unlock(&sweep.lock)
  24. }

并行式清扫,在 GC 初始化的时候就会启动 bgsweep(),然后在后台一直循环

  1. func bgsweep(c chan int) {
  2. sweep.g = getg()
  3. lock(&sweep.lock)
  4. sweep.parked = true
  5. c <- 1
  6. goparkunlock(&sweep.lock, "GC sweep wait", traceEvGoBlock, 1)
  7. for {
  8. for gosweepone() != ^uintptr(0) {
  9. sweep.nbgsweep++
  10. Gosched()
  11. }
  12. lock(&sweep.lock)
  13. if !gosweepdone() {
  14. // This can happen if a GC runs between
  15. // gosweepone returning ^0 above
  16. // and the lock being acquired.
  17. unlock(&sweep.lock)
  18. continue
  19. }
  20. sweep.parked = true
  21. goparkunlock(&sweep.lock, "GC sweep wait", traceEvGoBlock, 1)
  22. }
  23. }
  24. func gosweepone() uintptr {
  25. var ret uintptr
  26. systemstack(func() {
  27. ret = sweepone()
  28. })
  29. return ret
  30. }

不管是阻塞式还是并行式,都是通过 sweepone()函数来做清扫工作的.内存管理都是基于 span 的,mheap 是一个全局的变量,所有分配的对象都会记录在 mheap 中。在标记的时候,我们只要找到对对象对应的 span 进行标记,清扫的时候扫描 span,没有标记的 span 就可以回收了。

  1. // sweeps one span
  2. // returns number of pages returned to heap, or ^uintptr(0) if there is nothing to sweep
  3. func sweepone() uintptr {
  4. ...
  5. for {
  6. s := mheap_.sweepSpans[1-sg/2%2].pop()
  7. ...
  8. if !s.sweep(false) {
  9. // Span is still in-use, so this returned no
  10. // pages to the heap and the span needs to
  11. // move to the swept in-use list.
  12. npages = 0
  13. }
  14. }
  15. }
  16. // Sweep frees or collects finalizers for blocks not marked in the mark phase.
  17. // It clears the mark bits in preparation for the next GC round.
  18. // Returns true if the span was returned to heap.
  19. // If preserve=true, don't return it to heap nor relink in MCentral lists;
  20. // caller takes care of it.
  21. func (s *mspan) sweep(preserve bool) bool {
  22. ...
  23. }