go 1.5版本之后,如果你使用的map的key和value中都不包含指针,那么GC会忽略这个map。 (未调研不确定)
结论:
- 当结构中不存在指针时,触发GC后并不会释放堆上内存
- 当结构中存在指针时,触发GC后会释放一部分堆上内存
- 当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