Go version:
1 2
| 7384 ◯ go version go version go1.14.9 darwin/amd64
|
最近有这么个坑:
碰到内存泄露问题,大致是这样的:
- 1、定义一个全局map
- 2、给里面放值
- 3、用完之后删除Key/value
问题:map删除完key后,Mem有没有被释放?
观察内存变化:
情景1: 只删除Map的k/v
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| var intMap map[int]int var cnt = 8192
func main() { printMemStats() initMap() runtime.GC() printMemStats() log.Println(len(intMap)) for i := 0; i < cnt; i++ { delete(intMap, i) } log.Println(len(intMap)) runtime.GC() printMemStats() runtime.GC() printMemStats() } func initMap() { intMap = make(map[int]int, cnt) for i := 0; i < cnt; i++ { intMap[i] = i } } 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) }
|
输出:
1 2 3 4 5 6
| 2021/01/06 16:12:26 Alloc = 162 TotalAlloc = 162 Sys = 69714 NumGC = 0 2021/01/06 16:12:26 Alloc = 471 TotalAlloc = 487 Sys = 70290 NumGC = 1 2021/01/06 16:12:26 8192 2021/01/06 16:12:26 0 2021/01/06 16:12:26 Alloc = 473 TotalAlloc = 490 Sys = 70610 NumGC = 2 2021/01/06 16:12:26 Alloc = 475 TotalAlloc = 494 Sys = 70610 NumGC = 3
|
情景2: 删除map的k/v,并置map为nil
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| var intMap map[int]int var cnt = 8192
func main() { printMemStats() initMap() runtime.GC() printMemStats() log.Println(len(intMap)) for i := 0; i < cnt; i++ { delete(intMap, i) } log.Println(len(intMap)) runtime.GC() printMemStats() intMap = nil runtime.GC() printMemStats() } func initMap() { intMap = make(map[int]int, cnt) for i := 0; i < cnt; i++ { intMap[i] = i } } 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) }
|
输出:
1 2 3 4 5 6
| 2021/01/06 16:15:40 Alloc = 161 TotalAlloc = 161 Sys = 69714 NumGC = 0 2021/01/06 16:15:40 Alloc = 469 TotalAlloc = 484 Sys = 71696 NumGC = 1 2021/01/06 16:15:40 8192 2021/01/06 16:15:40 0 2021/01/06 16:15:40 Alloc = 471 TotalAlloc = 488 Sys = 71760 NumGC = 2 2021/01/06 16:15:40 Alloc = 160 TotalAlloc = 492 Sys = 71760 NumGC = 3
|
情景3: map放在函数中,并删除map的k/v,不置nil
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| var intMap map[int]int var cnt = 8192
func main() { printMemStats() other() runtime.GC() printMemStats() }
func other(){ initMap() runtime.GC() printMemStats() log.Println(len(intMap)) for i := 0; i < cnt; i++ { delete(intMap, i) } log.Println(len(intMap)) runtime.GC() printMemStats() } func initMap() { intMap = make(map[int]int, cnt) for i := 0; i < cnt; i++ { intMap[i] = i } } 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) }
|
输出:
1 2 3 4 5 6
| 2021/01/06 16:18:35 Alloc = 161 TotalAlloc = 161 Sys = 69458 NumGC = 0 2021/01/06 16:18:35 Alloc = 469 TotalAlloc = 484 Sys = 71440 NumGC = 1 2021/01/06 16:18:35 8192 2021/01/06 16:18:35 0 2021/01/06 16:18:35 Alloc = 471 TotalAlloc = 488 Sys = 71504 NumGC = 2 2021/01/06 16:18:35 Alloc = 473 TotalAlloc = 492 Sys = 71504 NumGC = 3
|
情景4: map放在函数中,并删除map的k/v,map置为nil
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| var intMap map[int]int var cnt = 8192
func main() { printMemStats() other() runtime.GC() printMemStats() }
func other(){ initMap() runtime.GC() printMemStats() log.Println(len(intMap)) for i := 0; i < cnt; i++ { delete(intMap, i) } log.Println(len(intMap)) runtime.GC() printMemStats() intMap = nil } func initMap() { intMap = make(map[int]int, cnt) for i := 0; i < cnt; i++ { intMap[i] = i } } 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) }
|
输出:
1 2 3 4 5 6
| 2021/01/06 16:20:02 Alloc = 161 TotalAlloc = 161 Sys = 69714 NumGC = 0 2021/01/06 16:20:02 Alloc = 469 TotalAlloc = 484 Sys = 70034 NumGC = 1 2021/01/06 16:20:02 8192 2021/01/06 16:20:02 0 2021/01/06 16:20:02 Alloc = 471 TotalAlloc = 488 Sys = 70098 NumGC = 2 2021/01/06 16:20:02 Alloc = 160 TotalAlloc = 492 Sys = 70098 NumGC = 3
|
情景5: map定义放在局部变量中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| var cnt = 8192
func main() { printMemStats() other() runtime.GC() printMemStats() }
func other() { var intMap map[int]int intMap = initMap(intMap) runtime.GC() printMemStats() log.Println(len(intMap)) for i := 0; i < cnt; i++ { delete(intMap, i) } log.Println(len(intMap)) runtime.GC() printMemStats() } func initMap(intMap map[int]int) map[int]int { intMap = make(map[int]int, cnt) for i := 0; i < cnt; i++ { intMap[i] = i } return intMap } 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) }
|
输出:
1 2 3 4 5 6
| 2021/01/06 16:29:54 Alloc = 161 TotalAlloc = 161 Sys = 69458 NumGC = 0 2021/01/06 16:29:54 Alloc = 469 TotalAlloc = 484 Sys = 71440 NumGC = 1 2021/01/06 16:29:54 8192 2021/01/06 16:29:54 0 2021/01/06 16:29:54 Alloc = 158 TotalAlloc = 488 Sys = 71504 NumGC = 2 2021/01/06 16:29:54 Alloc = 160 TotalAlloc = 491 Sys = 71504 NumGC = 3
|
汇编输出:
比较有意思的一行:
1 2 3
| XORL 异或运算符
XORL AX,AX --->将AX置0值
|
delete函数:
1
| 0x0125 00293 (../1126/main.go:26) CALL runtime.mapdelete_fast64(SB)
|
mapdelete_fast64函数作用:
点击Github查看
有意思的是:map的设计就是这样,删除key,只是把这个槽位置empty,并没有释放内存.
Others:
其它场景:
场景有很多,这里只是逻列最简单的,至于用指针之类的,有兴趣了再研究研究,方法都是一样的。
汇编代码生成