上卷 程序设计
中卷 标准库
- 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
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
7.2 队列
在清理 span 时,检查终结器,将终结函数打包成 finalizer 放到待执行队列。
// mgcsweep.go // Sweep frees or collects finalizers for blocks not marked in the mark phase. func (sl *sweepLocked) sweep(preserve bool) bool { s := sl.mspan spc := s.spanclass size := s.elemsize hadSpecials := s.specials != nil siter := newSpecialsIter(s) // 迭代 mspan.specials 上所有终结器。 for siter.valid() { // 计算所关联对象实际地址。 objIndex := uintptr(siter.s.offset) / size p := s.base() + objIndex*size // 检查扫描标记。如可回收,则可执行终结函数。 mbits := s.markBitsForIndex(objIndex) if !mbits.isMarked() { // 未标记,表示可回收。 // 1: 看看是否有终结器。 hasFin := false endOffset := p - s.base() + size // 因为 siter.s 可能是当前关联对象的 special 或 profile, // 所以要循环检查 kind,直到下个对象(offset > endOffset)。 for tmp := siter.s; tmp != nil && uintptr(tmp.offset) < endOffset; tmp = tmp.next { if tmp.kind == _KindSpecialFinalizer { // 因为有终结器要执行,所以重新激活对象(标记,下次回收)。 mbits.setMarkedNonAtomic() hasFin = true break } } // 2: 放入待运行队列。 for siter.valid() && uintptr(siter.s.offset) < endOffset { special := siter.s p := s.base() + uintptr(special.offset) if special.kind == _KindSpecialFinalizer || !hasFin { // 从链表移除。 siter.unlinkAndNext() // 释放 special,并将终结函数加入待运行队列。 freeSpecial(special, unsafe.Pointer(p), size) } else { siter.next() } } } else { // object is still live if siter.s.kind == _KindSpecialReachable { ... } else { // keep special record siter.next() } } } ... return false }
// mheap.go // freeSpecial performs any cleanup on special s and deallocates it. // s must already be unlinked from the specials list. func freeSpecial(s *special, p unsafe.Pointer, size uintptr) { switch s.kind { case _KindSpecialFinalizer: // 将终结函数加入队列。 sf := (*specialfinalizer)(unsafe.Pointer(s)) queuefinalizer(p, sf.fn, sf.nret, sf.fint, sf.ot) // 释放。 mheap_.specialfinalizeralloc.free(unsafe.Pointer(sf)) case _KindSpecialProfile: ... case _KindSpecialReachable: ... default: throw("bad special kind") panic("not reached") } }
待执行队列 finq,由多个 finblock 构成链表。每个 finblock 用数组存储一批 finalizer 对象。
// mfinal.go var finq *finblock // list of finalizers that are to be executed var finc *finblock // cache of free blocks type finblock struct { alllink *finblock next *finblock cnt uint32 _ int32 fin [(_FinBlockSize - 2*goarch.PtrSize - 2*4) / unsafe.Sizeof(finalizer{})]finalizer } type finalizer struct { fn *funcval // function to call (may be a heap pointer) arg unsafe.Pointer // ptr to object (may be a heap pointer) nret uintptr // bytes of return values from fn fint *_type // type of first argument of fn ot *ptrtype // type of ptr to object (may be a heap pointer) }
// mfinal.go func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot *ptrtype) { // 队列未分配或已满,重新申请。 if finq == nil || finq.cnt == uint32(len(finq.fin)) { // 缓存为空,分配。 if finc == nil { finc = (*finblock)(persistentalloc(_FinBlockSize, 0, &memstats.gcMiscSys)) finc.alllink = allfin allfin = finc } // 从缓存取一个 block 加入 finq 链表头部。 block := finc finc = block.next block.next = finq finq = block } // 取一个空位。 f := &finq.fin[finq.cnt] atomic.Xadd(&finq.cnt, +1) // 设置属性。 f.fn = fn f.nret = nret f.fint = fint f.ot = ot f.arg = p // 唤醒标记。 fingwake = true }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论