golang MAP底层内存扩展实验

stvenyin · · 1094 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

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.

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1094 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传