上卷 程序设计
中卷 标准库
- 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.4 池
与 mcentral 类似,有个全局 stackpool 负责平衡,为 mcache.stackcache 提供后备内存。
// stack.go // Global pool of spans that have free stacks. // Stacks are assigned an order according to size. // order = log_2(size/FixedStack) // There is a free list for each order. var stackpool [_NumStackOrders]struct { item stackpoolItem } type stackpoolItem struct { mu mutex span mSpanList }
// mheap.go // mSpanList heads a linked list of spans. type mSpanList struct { first *mspan last *mspan } type mspan struct { manualFreeList gclinkptr // list of free objects in mSpanManual spans }
- stackpoolItem.span: 多个 mspan 构成的链表。
- mspan.manualFreeList: 切分好可供复用的栈内存。
本地缓存不足,从 stackpool 扩容。
// stack.go // stackcacherefill/stackcacherelease implement a global pool of stack segments. // The pool is required to prevent unlimited growth of per-thread caches. func stackcacherefill(c *mcache, order uint8) { // Grab some stacks from the global cache. // Grab half of the allowed capacity (to prevent thrashing). var list gclinkptr var size uintptr lock(&stackpool[order].item.mu) for size < _StackCacheSize/2 { x := stackpoolalloc(order) x.ptr().next = list list = x size += _FixedStack << order } unlock(&stackpool[order].item.mu) c.stackcache[order].list = list c.stackcache[order].size = size }
// Allocates a stack from the free pool. Must be called with // stackpool[order].item.mu held. func stackpoolalloc(order uint8) gclinkptr { // 从链表提取 span。 list := &stackpool[order].item.span s := list.first // 如 span 为空。 if s == nil { // 从堆获取新内存块。 s = mheap_.allocManual(_StackCacheSize>>_PageShift, spanAllocStack) osStackAlloc(s) // 切分,串成链表。 s.elemsize = _FixedStack << order for i := uintptr(0); i < _StackCacheSize; i += s.elemsize { x := gclinkptr(s.base() + i) x.ptr().next = s.manualFreeList s.manualFreeList = x } // 插入 span 链表。 list.insert(s) } // 提取内存块。 x := s.manualFreeList s.manualFreeList = x.ptr().next s.allocCount++ // 该 span 没有剩余内存,从链表移除。 if s.manualFreeList.ptr() == nil { // all stacks in s are allocated. list.remove(s) } return x }
而当本地数量过多时,则归还部分给全局池。
// stack.go func stackcacherelease(c *mcache, order uint8) { x := c.stackcache[order].list size := c.stackcache[order].size lock(&stackpool[order].item.mu) for size > _StackCacheSize/2 { y := x.ptr().next stackpoolfree(x, order) x = y size -= _FixedStack << order } unlock(&stackpool[order].item.mu) c.stackcache[order].list = x c.stackcache[order].size = size }
// Adds stack x to the free pool. // Must be called with stackpool[order].item.mu held. func stackpoolfree(x gclinkptr, order uint8) { // 所在 span。 s := spanOfUnchecked(uintptr(x)) // 如该 span 内存块链表为空,直接放回。 if s.manualFreeList.ptr() == nil { // s will now have a free stack stackpool[order].item.span.insert(s) } // 放回 span 内存块链表。 x.ptr().next = s.manualFreeList s.manualFreeList = x s.allocCount-- // 如果该 span 内存被全部收回,则将其归还给堆。 if gcphase == _GCoff && s.allocCount == 0 { // Span is completely free. Return it to the heap // immediately if we're sweeping. stackpool[order].item.span.remove(s) s.manualFreeList = 0 osStackFree(s) mheap_.freeManual(s, spanAllocStack) } }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论