SetFinalizer设置一个finalizer关联到一个对象obj,当垃圾回收准备回收obj的时候,它会断开这个连接,并在单独的goroutine中执行finalizer(obj),这将让obj再次可用,但是不会再关联finalizer,
在SetFinalizer中:
- 先检查元素,如果类型为nil,或者不为指针,元素值为nil 都会报错
- 查找对象的heap地址
- 如果是函数类型为nil,则移除removefinalizer
- 检测参数类型,并给计算返回值size
createfing()
确保finalizer goroutine正在运行- 添加finalizer
func SetFinalizer(obj interface{}, finalizer interface{}) {
e := efaceOf(&obj)
etyp := e._type
if etyp == nil {
throw("runtime.SetFinalizer: first argument is nil")
}
if etyp.kind&kindMask != kindPtr {
throw("runtime.SetFinalizer: first argument is " + etyp.string() + ", not pointer")
}
ot := (*ptrtype)(unsafe.Pointer(etyp))
if ot.elem == nil {
throw("nil elem type!")
}
// find the containing object
base, _, _ := findObject(uintptr(e.data), 0, 0)
f := efaceOf(&finalizer)
ftyp := f._type
if ftyp == nil {
// switch to system stack and remove finalizer
systemstack(func() {
removefinalizer(e.data)
})
return
}
fint := ft.in()[0]
// make sure we have a finalizer goroutine
createfing()
systemstack(func() {
if !addfinalizer(e.data, (*funcval)(f.data), nret, fint, ot) {
throw("runtime.SetFinalizer: finalizer already set")
}
})
}
从mheap.specialfinalizeralloc中申请一块内存,然后调用addspecial
,如果成功则返回,失败则free掉刚才申请的内存
在addspecial
,根据p指针找到对应的span,轮训找到是否有相同offset和kind的数据存在,如果存在则finalizer函数已经存在,否则将其加入到span.specials
中去(这里有根据offset排序)
// Adds a finalizer to