map的容量的获取
在go语言中,有两个内建函数分别是len(),cap(),前者用于获取容器的具体内容个数,后者用于获取容器分配的容量大小,但是这个cap对象是不能获取到map具体分配的容量大小的。有没有办法获取到呢,办法是有的,且看下文。
首先我们先使用gdb调试工具,查看一下map对象的具体结构是什么样子的。
一个及其简单的代码如下:
package main
func main() {
m := make(map[string]int)
m["a"] = 1
m["b"] = 2
}
接下来我们编译这个简单的代码,并进行调试
# go build -o test -gcflags="-N -l" main.go 这里goflags是编译时指定的参数, -N 表示禁止优化,-l表示禁止内联。 便于调试
使用gdb进行调试
# gdb test
(gdb) b main.main
Breakpoint 1 at 0x401000: file /media/sf_goproject/src/map.go, line 3.
(gdb) r # 开始运行
Starting program: /media/sf_goproject/src/test
(gdb) n
m := make(map[string]int)
(gdb) ptype mtype = struct hash<string, int> {
int count;
uint8 flags;
uint8 B;
uint32 hash0;
struct bucket<string, int> *buckets;
struct bucket<string, int> *oldbuckets;
uintptr nevacuate;
[2]*[]*runtime.bmap *overflow;
} *
从上面的调试可以看到map对象的数据结构,在golang的runtime包的的haspmap.go中有这个结构的详细介绍:
// A header for a Go map.
type hmap struct {
// Note: the format of the Hmap is encoded in ../../cmd/internal/gc/reflect.go and
// ../reflect/type.go. Don't change this structure without also changing that code!
count int // # live cells == size of map. Must be first (used by len() builtin)
flags uint8
B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
hash0 uint32 // hash seed
buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
// If both key and value do not contain pointers and are inline, then we mark bucket
// type as containing no pointers. This avoids scanning such maps.
// However, bmap.overflow is a pointer. In order to keep overflow buckets
// alive, we store pointers to all overflow buckets in hmap.overflow.
// Overflow is used only if key and value do not contain pointers.
// overflow[0] contains overflow buckets for hmap.buckets.
// overflow[1] contains overflow buckets for hmap.oldbuckets.
// The first indirection allows us to reduce static size of hmap.
// The second indirection allows to store a pointer to the slice in hiter.
overflow *[2]*[]*bmap
}
所以B代表了map的容量 既然我们知道了数据的的结构,便可根据结构得到容量的内容。代码示例如下。
package main
type hmap struct {
count int
flags uint8
B uint8
hash0 uint32
buckets unsafe.Pointer
oldbuckets unsafe.Pointer
}
func main() {
m := make(map[string]string)
c, b := getInfo(m)
fmt.Println("count: ", c, "b: ", b)
for i := 0; i < 10000; i++ {
m[strconv.Itoa(i)] = strconv.Itoa(i)
if i%200 == 0 {
c, b := getInfo(m)
cap := math.Pow(float64(2), float64(b))
fmt.Printf("count: %d, b: %d, load: %f\n", c, b, float64(c)/cap)
}
}
println("开始删除------")
for i := 0; i < 10000; i++ {
delete(m, strconv.Itoa(i))
if i%200 == 0 {
c, b := getInfo(m)
cap := math.Pow(float64(2), float64(b))
fmt.Println("count: ", c, "b:", b, "load: ", float64(c)/cap)
}
}
debug.FreeOSMemory()
c, b = getInfo(m)
fmt.Println("释放后: ", "count: ", c, "b:", b)
}
func getInfo(m map[string]string) (int, int) {
point := (**hmap)(unsafe.Pointer(&m))
value := *point
return value.count, int(value.B)
}
一些记录:
1. 在看许多文章中有说到map分配的键值被删除之后,内存是不会释放的。但是在我测试的过程中,发现内存是可以释放的。可能是版本的原因,测试的版本是1.7.1
2. map是非并发安全的,使用过程中需要自己去控制加锁。
map的容量的获取的更多相关文章
- 在map中根据value获取key
原文:http://blog.csdn.net/mexican_jacky/article/details/51789548 //根据map的value获取map的key private static ...
- map中根据value获取key
public static String getKeyByValue(Map map, Object value) { String keys=""; Iterator it = ...
- java map遍历、排序,根据value获取key
Map 四种遍历: Map<String,String> map = new HashMap<String, String>(); map.put("one" ...
- java里面获取map的key和value的方法
获取map的key和value的方法分为两种形式: map.keySet():先获取map的key,然后根据key获取对应的value: map..entrySet():同时查询map的key和val ...
- Map四种获取key和value值的方法,以及对map中的元素排序(转)
获取map的值主要有四种方法,这四种方法又分为两类,一类是调用map.keySet()方法来获取key和value的值,另一类则是通过map.entrySet()方法来取值,两者的区别在于,前者主要是 ...
- C++ map通过key获取value
c++的map中通过key获取value的方法 一般是value =map[key],或者另一种迭代器的方式 1.在map中,由key查找value时,首先要判断map中是否包含key. 2.如果不 ...
- cocos基础教程(5)数据结构介绍之cocos2d::Map<K,V>
1.概述 cocos2d::Map<K,V> 是一个内部使用了 std::unordered_map的关联容器模版. std::unordered_map 是一个存储了由key-value ...
- ceph之crush map
编辑crush map: 1.获取crush map: 2.反编译crush map: 3.至少编辑一个设备,桶, 规则: 4.重新编译crush map: 5.重新注入crush map: 获取cr ...
- Map笔记
Map,是一个接口,是以键值对的方式存储的,并且键是无序且不可重复的.Map和Collection没有什么关系,Map是一对一对的存,而Collection是一个一个的存. 下面有一个子接口:Sort ...
随机推荐
- wx.setStorageSync(KEY,DATA)
wx.setStorageSync 每个微信小程序都可以有自己的本地缓存,可以通过wx.setStorage(wx.setStorageSync).wx.getStorage(wx.getStorag ...
- hibernate增删改
public class HibernateUtils { private static SessionFactory sessionFactory=null; static{ //获取config ...
- CentOS 6 安装Redmine
Redmine是一个灵活的项目管理web应用,采用Ruby on Rails框架开发.Redmine是典型的web 2.0网站,项目管理系统的后起之秀.Redmine支持多项目,灵活的角色权限管理,灵 ...
- 当Windows Phone遇到Windows 8
三年前,Windows Phone系统的发布表示了微软夺回移动市场的决心.一年前,Windows 8的发布,昭示着Windows Phone系统取得的成功——扁平化图标风格.动态磁贴.SkyDrive ...
- jQuery插件初级练习3
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- 7.Git与项目
Git简介 Git是目前世界上最先进的分布式版本控制系统 安装 sudo apt-get install git 安装成功后,运行如下命令 git 产生 Linus在1991年创建了开源的Linux, ...
- Android-Java-面向对象与面向过程的简单理解
支持面向过程的语言有:C Basic 等语言: 支持面向对象的语言有:C++ Java C# 等语言: 面向过程:操作的是行为/功能: 面向对象:操作的是对象,而对象里面有功能行为,所以可以指定 ...
- MySQL--binlog和relay log的生成和删除
##================================================================================================== ...
- C#常用修饰符
访问修饰符 访问修饰符是一些关键字,用于指定声明的成员或类型的可访问性,C#有4个访问修饰符:public.private.protected.internal,使用这些访问修饰符可以指定以下5个访问 ...
- 背水一战 Windows 10 (42) - 控件(导航类): Frame 动画
[源码下载] 背水一战 Windows 10 (42) - 控件(导航类): Frame 动画 作者:webabcd 介绍背水一战 Windows 10 之 控件(导航类) Frame 动画 示例An ...