上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
4.6.6 垃圾回收
在垃圾标记的 markroot 里,引发 dead Gs 栈内存回收操作。
// mgcmark.go func markroot(gcw *gcWork, i uint32, flushBgCredit bool) int64 { switch { case i == fixedRootFreeGStacks: systemstack(markrootFreeGStacks) } }
// mgcmark.go // 释放 dead Gs 栈内存。 func markrootFreeGStacks() { // Take list of dead Gs with stacks. list := sched.gFree.stack sched.gFree.stack = gList{} if list.empty() { return } // Free stacks. q := gQueue{list.head, list.head} for gp := list.head.ptr(); gp != nil; gp = gp.schedlink.ptr() { stackfree(gp.stack) gp.stack.lo = 0 gp.stack.hi = 0 // Manipulate the queue directly since the Gs are // already all linked the right way. q.tail.set(gp) } // Put Gs back on the free list. sched.gFree.noStack.pushAll(q) }
其次,在垃圾扫描结束时,释放 stackpool 内存块,回收 mcache.stackcache 缓存。
// mgc.go func gcMarkTermination(nextTriggerRatio float64) { systemstack(freeStackSpans) systemstack(func() { forEachP(func(_p_ *p) { _p_.mcache.prepareForSweep() // stackcache_clear(c) }) }) }
// stack.go // freeStackSpans frees unused stack spans at the end of GC. func freeStackSpans() { // 池内小块。 for order := range stackpool { list := &stackpool[order].item.span for s := list.first; s != nil; { next := s.next // 内存全部收回。 if s.allocCount == 0 { // 从链表移除。 list.remove(s) s.manualFreeList = 0 // 释放。 osStackFree(s) mheap_.freeManual(s, spanAllocStack) } s = next } } // 大块。 for i := range stackLarge.free { for s := stackLarge.free[i].first; s != nil; { next := s.next // 从链表移除。 stackLarge.free[i].remove(s) // 释放。 osStackFree(s) mheap_.freeManual(s, spanAllocStack) s = next } } }
// mcache.go, stack.go func (c *mcache) prepareForSweep() { stackcache_clear(c) } func stackcache_clear(c *mcache) { for order := uint8(0); order < _NumStackOrders; order++ { x := c.stackcache[order].list for x.ptr() != nil { y := x.ptr().next stackpoolfree(x, order) x = y } c.stackcache[order].list = 0 c.stackcache[order].size = 0 } }
最后,对 G 进行栈内存收缩。
// mgcmark.go func markroot(gcw *gcWork, i uint32, flushBgCredit bool) int64 { switch { default: scanstack(gp, gcw) } } func scanstack(gp *g, gcw *gcWork) int64 { shrinkstack(gp) }
// stack.go func shrinkstack(gp *g) { // 1/2 oldsize := gp.stack.hi - gp.stack.lo newsize := oldsize / 2 if newsize < _FixedStack { return } // 已用空间不足 1/4 时才收缩。 avail := gp.stack.hi - gp.stack.lo if used := gp.stack.hi - gp.sched.sp + _StackLimit; used >= avail/4 { return } // 分配新栈(小),并复制数据。 copystack(gp, newsize) }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论