检查来源
尽管这在任何地方都没有记录,但请检查来源:runtime/hashmap.go, mapdelete()
功能:
558 func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
// ...
600 memclr(k, uintptr(t.keysize))
601 v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*uintptr(t.keysize) + i*uintptr(t.valuesize))
602 memclr(v, uintptr(t.valuesize))
// ...
618 }
如您所见,键(第 #600 行)和值(第 #602 行)的存储都被清除/清零。
这意味着如果任何键或值是指针,或者它们是包含指针的复杂类型的值,它们将被归零,因此指向的对象不再被映射的内部数据结构引用,因此没有内存这里泄漏。
当没有更多参考完整的map
值,则完整的内存区域map
将被垃圾收集,并且键和值中包含的所有指针也不再由映射保存;如果没有其他人引用这些指向的对象,它们将被正确地垃圾收集。
构造一个例子来证明这一点
我们还可以构建一个测试代码来证明这一点,而无需检查来源:
type point struct {
X, Y int
}
var m = map[int]*point{}
func main() {
fillMap()
delete(m, 1)
runtime.GC()
time.Sleep(time.Second)
fmt.Println(m)
}
func fillMap() {
p := &point{1, 2}
runtime.SetFinalizer(p, func(p *point) {
fmt.Printf("Finalized: %p %+v\n", p, p)
})
m[1] = p
fmt.Printf("Put in map: %p %+v\n", p, p)
}
输出(尝试一下去游乐场):
Put in map: 0x1040a128 &{X:1 Y:2}
Finalized: 0x1040a128 &{X:1 Y:2}
map[]
这是做什么的?它创建了一个*Point
value(指向结构体的指针),将其放入映射中,并注册一个函数should当该指针变得无法访问时调用(使用runtime.SetFinalizer()),然后删除包含该指针的条目。然后我们打电话runtime.GC()“强制”立即进行垃圾收集。我还在最后打印地图,只是为了确保整个地图不会由于某些优化而被垃圾收集。
结果?我们看到注册的函数被调用,这证明指针已从映射中删除,因为delete()
调用,因为(因为我们没有其他引用它)它有资格进行垃圾收集。