上卷 程序设计
中卷 标准库
- 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 池
与 central 类似,有个全局 stackpool 负责平衡和提供后备内存。
// 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 }
扩容
当分配操作在 cache 找不到可用内存时,便从 pool 扩容。
// 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 // 循环提取,直到达到一半上限容量。 for size < _StackCacheSize/2 { x := stackpoolalloc(order) x.ptr().next = list list = x size += _FixedStack << order } c.stackcache[order].list = list c.stackcache[order].size = size }
丛 heap 取 span 后,会将内存分割成多块,构成链表(span.manualFreeList)。
从该链表提取。如果链表为空,则将该 span 从 pool 移除。
// stack.go // Allocates a stack from the free pool. Must be called with // stackpoolmu held. func stackpoolalloc(order uint8) gclinkptr { // 从链表找到对应等级的 span。 list := &stackpool[order].item.span s := list.first // 如果为空,则从堆获取。 if s == nil { // 按上限从 heap 取 span。 s = mheap_.allocManual(_StackCacheSize>>_PageShift, &memstats.stacks_inuse) 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) } // 从 span 分出一块,用于返回。 x := s.manualFreeList s.manualFreeList = x.ptr().next s.allocCount++ // 如果 span 没有剩余空间,则从链表移除。 if s.manualFreeList.ptr() == nil { list.remove(s) } return x }
释放
当释放操作发现 cache 里缓存过多,则归还一些给 pool。
// stack.go func stackcacherelease(c *mcache, order uint8) { x := c.stackcache[order].list size := c.stackcache[order].size // 上交,保留一半。 for size > _StackCacheSize/2 { y := x.ptr().next stackpoolfree(x, order) x = y size -= _FixedStack << order } c.stackcache[order].list = x c.stackcache[order].size = size }
// Adds stack x to the free pool. func stackpoolfree(x gclinkptr, order uint8) { // 根据地址找到对应 span。 s := spanOfUnchecked(uintptr(x)) // 马上有剩余空间,放回 pool 链表。 if s.manualFreeList.ptr() == nil { stackpool[order].item.span.insert(s) } // 将空间放回 span 内的切分链表。 x.ptr().next = s.manualFreeList s.manualFreeList = x s.allocCount-- // 如果 span 收回全部空间,归还给 heap。 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 mheap_.freeManual(s, &memstats.stacks_inuse) } }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论