上卷 程序设计
中卷 标准库
- 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 里,引发栈内存回收操作。
// mgcmark.go func markroot(gcw *gcWork, i uint32) { flushmcache(int(i - baseFlushCache)) systemstack(markrootFreeGStacks) }
函数 flushmcache 除收回用于分配的内存外,还会清理栈缓存。
// mstats.go func flushmcache(i int) { stackcache_clear(c) }
将 cache 里保存的 stack 内存全部交回 pool。
如 span 收回全部空间,则返还给 heap。
// stack.go 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 } }
而 markrootFreeGStacks 则回收 dead G 所持有栈内存。
// mgcmark.go // markrootFreeGStacks frees stacks of 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 q.tail.set(gp) } // Put Gs back on the free list. sched.gFree.noStack.pushAll(q) }
在 markroot 对 Grunnable、Gsyscall、Gwaiting G.stack 扫描时,也会进行栈内存收缩。
markroot -> scanstack -> shrinkstack。
// stack.go func shrinkstack(gp *g) { oldsize := gp.stack.hi - gp.stack.lo newsize := oldsize / 2 // Don't shrink the allocation below the minimum-sized stack allocation. if newsize < _FixedStack { return } // 通过 SP 位置计算已使用空间。 // 如果不足 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) }
到垃圾扫描结束阶段,会进一步清理栈相关缓存。
// mgc.go func gcMarkTermination(nextTriggerRatio float64) { // Free stack spans. This must be done between GC cycles. systemstack(freeStackSpans) }
// stack.go // freeStackSpans frees unused stack spans at the end of GC. func freeStackSpans() { // 清理 pool 里的内存。 for order := range stackpool { list := &stackpool[order].item.span for s := list.first; s != nil; { next := s.next // 如果收回全部空间,归还给 heap。 if s.allocCount == 0 { list.remove(s) s.manualFreeList = 0 mheap_.freeManual(s, &memstats.stacks_inuse) } s = next } } // 清理大块缓存。 for i := range stackLarge.free { for s := stackLarge.free[i].first; s != nil; { next := s.next stackLarge.free[i].remove(s) mheap_.freeManual(s, &memstats.stacks_inuse) s = next } } }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论