橡皮擦擦

golang map使用delete()删除key后GC是否能正常回收

Golang

go 1.5版本之后,如果你使用的map的key和value中都不包含指针,那么GC会忽略这个map。 (未调研不确定)

结论:

  1. 当结构中不存在指针时,触发GC后并不会释放堆上内存
  2. 当结构中存在指针时,触发GC后会释放一部分堆上内存
  3. 当map被设置为nil时,触发GC后会直接回收所占堆上内存

测试代码:

type PutKvsCASInput_KvsCAS struct {
   Key      string `protobuf:"bytes,1,opt,name=Key" json:"Key,omitempty"`
   Value    string `protobuf:"bytes,2,opt,name=Value" json:"Value,omitempty"`
   IsCAS    bool   `protobuf:"varint,3,opt,name=IsCAS" json:"IsCAS,omitempty"`
   Index    uint64 `protobuf:"varint,4,opt,name=Index" json:"Index,omitempty"`
   IsDelete bool   `protobuf:"varint,5,opt,name=IsDelete" json:"IsDelete,omitempty"`
}
var intMap map[int]PutKvsCASInput_KvsCAS
var cnt = 8192
func main() {
   printMemStats("初始化状态")
   initMap()
   runtime.GC()
   printMemStats("触发一次GC后")
   fmt.Println(fmt.Sprintf("当前map长度:%d", len(intMap)))
   // 删除所有key
   for i := 0; i < cnt; i++ {
      delete(intMap, i)
   }
   fmt.Println(fmt.Sprintf("删除所有key后长度:%d", len(intMap)))
   runtime.GC()
   printMemStats("触发第二次GC")
   intMap = nil
   runtime.GC()
   printMemStats("设置map为nil后的GC")
}
func initMap() {
   intMap = make(map[int]PutKvsCASInput_KvsCAS, cnt)
   for i := 0; i < cnt; i++ {
      intMap[i] = PutKvsCASInput_KvsCAS{}
   }
}
func printMemStats(message string) {
   var m runtime.MemStats
   runtime.ReadMemStats(&m)
   log.Printf("STEP:%s, 当前堆内存 = %v 堆上总分配 = %v 申请的系统内存 = %v GC次数 = %v\n", message, m.Alloc/1024, m.TotalAlloc/1024, m.Sys/1024, m.NumGC)
}

运行结果:

2021/08/13 17:56:19 STEP:初始化状态, 当前堆内存 = 162 堆上总分配 = 162 申请的系统内存 = 69715 GC次数 = 0
2021/08/13 17:56:19 STEP:触发一次GC后, 当前堆内存 = 1283 堆上总分配 = 1297 申请的系统内存 = 70290 GC次数 = 1
当前map长度:8192
删除所有key后长度:0
2021/08/13 17:56:19 STEP:触发第二次GC, 当前堆内存 = 1283 堆上总分配 = 1298 申请的系统内存 = 70354 GC次数 = 2 (此时所占用内存没有变化)
2021/08/13 17:56:19 STEP:设置map为nil后的GC, 当前堆内存 = 157 堆上总分配 = 1302 申请的系统内存 = 70610 GC次数 = 3
点我评论
打赏本文
二维码


51

文章

6

分类