本想写一篇关于 golang 中 map 底层的文章, 但是发现已经了相当不错的文章 – 字节跳动技术团队 - Golang 中 map 探究 这里只补充一下,缺少的 map 的删除操作

内部数据结构

初始化

map 是一个有"包含内容"的数据结构, 使用之前需要提前初始化, 即调用make

真正是调用源码是 runtime.makemap

获取数据

删除

源码地址

删除的关键代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

			// Only clear key if there are pointers in it.
			// # 当 Key 是指针类型的时候会去清空指针
			if t.key.ptrdata != 0 {
				if goarch.PtrSize == 8 {
					*(*unsafe.Pointer)(k) = nil
				} else {
					// There are three ways to squeeze at one ore more 32 bit pointers into 64 bits.
					// Just call memclrHasPointers instead of trying to handle all cases here.
					memclrHasPointers(k, 8)
				}
			}
			
			e := add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.elemsize))
			// # 当 Value 为指针类型的时候, 指针为空, 解除引用 -> GC
			if t.elem.ptrdata != 0 {
				memclrHasPointers(e, t.elem.size)
			} else {
				memclrNoHeapPointers(e, t.elem.size)
			}
		
			// # 讲 hash 值标记为空
			b.tophash[i] = emptyOne

上述删除代码操作现象

  • mapvalue类型中包含引用类型, 删除对应的key之后, 经过GC就会释放占用的内存
  • mapvalue 类型不包含引用类型, 删除对应的key之后, GC无法释放类型

可以查看我自己的实验结果 {{}}

https://ynikl.github.io/blog/golang-memory-analyze-with-runtime/

扩容

参考

Golang 中 map 探究