zoukankan      html  css  js  c++  java
  • 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 m

    type = 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
    ", 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是非并发安全的,使用过程中需要自己去控制加锁。

  • 相关阅读:
    Spring Boot 2.1.10 学习笔记(2)
    Spring Boot 2.1.10 学习笔记(1)
    Win10 下载与激活 MSDN
    Java JDK 1.8 下载及其版本说明 8u202(最后一个免费版)
    shell函数开发意见优化系统脚本
    php大文件下载支持断点续传
    xunsearch使用笔记
    微信使用的curl方法
    php执行sql语句打印结果
    二维数组排序:array_orderby(php官网评论)
  • 原文地址:https://www.cnblogs.com/qiumingcheng/p/9948472.html
Copyright © 2011-2022 走看看