开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情
最初的map在设计时没有delete函数,想要删除元素,赋值false。具体可以查看以下三个历史issue。
github.com/golang/go/i…
github.com/golang/go/i…
相关语法:
m[k] = nil, false
go1.0提供内置函数delete,可以从map中删除一组键值对,即使key不存在也保证删除操作的安全性。具体介绍:go.dev/blog/maps
但是内存并没有被释放,只是修改了一个标记,底层数组还是被占用着。
同时,根据key类型不同,会优化成更具体的删除函数。mapdelete_fast32/mapdelete_fast64/mapdelete_faststr (runtime/map)
相关代码测试:
var intMap map[int]int
var cnt = 8192
func main() {
// alloc = 123 TotalAlloc = 123 Sys = 8067 NumGC = 0
printMemStats()
initMap()
runtime.GC()
// alloc = 428 TotalAlloc = 443 Sys = 8706 NumGC = 1
printMemStats()
// 8192
log.Println(len(intMap))
for i := 0; i < cnt; i++ {
delete(intMap, i)
}
// 0
log.Println(len(intMap))
runtime.GC()
// alloc = 430 TotalAlloc = 446 Sys = 8962 NumGC = 2
printMemStats()
intMap = nil
// alloc = 431 TotalAlloc = 447 Sys = 8706 NumGC = 2
printMemStats()
runtime.GC()
// alloc = 120 TotalAlloc = 450 Sys = 9218 NumGC = 3
printMemStats()
}
func printMemStats() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
log.Printf("alloc = %v TotalAlloc = %v Sys = %v NumGC = %v\n", m.Alloc/1024, m.TotalAlloc/1024, m.Sys/1024, m.NumGC)
}
func initMap() {
intMap = make(map[int]int, cnt)
for i := 0; i < cnt; i++ {
intMap[i] = i
}
}
- Alloc 当前堆上对象占用的内存大小 KB
- TotalAlloc 堆上总共分配的内存大小
- Sys 程序从操作系统总共申请的内存大小 KB
- NumGC 垃圾回收的次数
调用delete进行删除元素时,虽然map的长度返回为0,但当前堆上对象占用的内存大小并没有改变。
但是将map置为nil后,进行gc,会发现当前堆上对象占用的内存大小变小。
同时,对于delete()没有返回值,但是对于sync.Map会返回bool值检查存在性。因为对于map来说,调用者通常知道元素是否存在,或者根本就不关心。
参考
总结
map删除元素并不会释放内存,只是修改标记。如果想要释放内存,可以将map设置为nil后调用gc来实现。