package main
import (
"fmt"
"runtime"
)
//笔者使用 map 作为一个全局的 cache
//测试之后发现,即使删除了不需要使用key,
// 但随着写入数据量的增加,map
//占用的内存也开始不断增加。
//分析原因,map 是通过key 和 hash 值来分布和查找对象。
//map 不会收缩「不再使用」的空间,
// 即使把 map 中的键值对,
//它依然保留内存空间继续使用。
var intMap map[int]int
var cnt = 8192
func initMap() {
intMap = make(map[int]int, cnt)
for i := 0; i < cnt; i++ {
intMap[i] = i
}
}
//预估MAP容量
func test(m map[int]int) {
for i := 0; i < 10000; i++ {
m[i] = i
}
}
//带容量的初始化
func BenchmarkMapCap() {
for i := 0; i < 10000; i++ {
m := make(map[int]int, 10000) //带容量的初始化
test(m)
fmt.Println(m)
}
}
func printMemStats() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("HeapAlloc = %v HeapIdel= %v HeapSys = %v HeapReleased = %v\n", m.HeapAlloc/1024, m.HeapIdle/1024, m.HeapSys/1024, m.HeapReleased/1024)
}
//清空 map 不等于释放内存
//map源码实现
//map的实现
//Go中的map在底层是用哈希表实现的,你可以在 $GOROOT/src/pkg/runtime/hashmap.goc 找到它的实现。
//数据结构
//哈希表的数据结构中一些关键的域如下所示:
//struct Hmap
//{
//uint8 B; // 可以容纳2^B个项
//uint16 bucketsize; // 每个桶的大小
//byte *buckets; // 2^B个Buckets的数组
//byte *oldbuckets; // 前一个buckets,只有当正在扩容时才不为空
//};
//根据key算出hash值,进而得出对应的bucket。
//如果bucket在old table中,将其重新散列到new table中。
//在bucket中,查找空闲的位置,如果已经存在需要插入的key,更新其对应的value。
//根据table中元素的个数,判断是否grow table。
//如果对应的bucket已经full,重新申请新的bucket作为overbucket。
//将key/value pair插入到bucket中。
func main() {
//
BenchmarkMapCap()
//程序启动占用内存
//printMemStats()
//map 第一次初始化
//initMap()
//runtime.GC()
//printMemStats()
//fmt.Printf("map len's %d\n", len(intMap))
//for i := 0; i < cnt; i++ {
//delete 所有 key
//delete(intMap, i)
//}
//fmt.Printf("map len's %d\n", len(intMap))
//runtime.GC()
//printMemStats()
//map 置为nil
//intMap = nil
//runtime.GC()
//printMemStats()
//map 第二次初始化
//initMap()
//runtime.GC()
//printMemStats()
}
// GO 调度器
//HeapSys:程序向应用程序申请的内存
//
//HeapAlloc:堆上目前分配的内存
//
//HeapIdle:堆上目前没有使用的内存
//
//HeapReleased:回收到操作系统的内存
//结论
//delete map 中的所有 key,map 占用内存仍处于「使用状态」,map 置为 nil,map 占用的内存处于「空闲状态」。
//处于空闲状态内存,一定时间内在下次申请的可重复被使用,不必再向操作系统申请。
1.运行结果
【】
![Untitled.png](https://static.studygolang.com/181219/4856c02a05e3098fac181daeb3ded072.png)
func main() {
//
BenchmarkMapCap()
//程序启动占用内存
printMemStats()
//map 第一次初始化
initMap()
runtime.GC()
printMemStats()
fmt.Printf("map len's %d\n", len(intMap))
for i := 0; i < cnt; i++ {
//delete 所有 key
delete(intMap, i)
}
fmt.Printf("map len's %d\n", len(intMap))
runtime.GC()
printMemStats()
//map 置为nil
intMap = nil
runtime.GC()
printMemStats()
//map 第二次初始化
initMap()
runtime.GC()
printMemStats( )
}
![Untitled1.png](https://static.studygolang.com/181219/15bab5882839bc8bd74f10a07847b2ec.png)
end.
有疑问加站长微信联系(非本文作者)