Memory overhead of maps in Go

前端 未结 5 1963
谎友^
谎友^ 2020-12-31 18:42

map[byte]byte{0:10} should be using least 2 bytes, one for value and one per key. But as each hashmap implmentation, there is also a hidden cost per item. What is the memory

5条回答
  •  天涯浪人
    2020-12-31 19:26

    Here's a cross-platform reimplementation of Nick's program. It includes changes where I think it was flawed. It also adds more measured data points.

    Note: To allow for a wider "entries" range, the measured map bellow is map[int16]byte.

    package main
    
    import (
            "fmt"
            "runtime"
            "unsafe"
    )
    
    func Alloc() uint64 {
            var stats runtime.MemStats
            runtime.GC()
            runtime.ReadMemStats(&stats)
            return stats.Alloc - uint64(unsafe.Sizeof(hs[0]))*uint64(cap(hs))
    }
    
    var hs = []*map[int16]byte{}
    
    func main() {
            hs := []*map[int16]byte{}
            n := 1000
            before := Alloc()
            for i := 0; i < n; i++ {
                    h := map[int16]byte{}
                    hs = append(hs, &h)
            }
            after := Alloc()
            emptyPerMap := float64(after-before) / float64(n)
            fmt.Printf("Bytes used for %d empty maps: %d, bytes/map %.1f\n", n, after-before, emptyPerMap)
            hs = nil
    
            k := 1
            for p := 1; p < 16; p++ {
                    before = Alloc()
                    for i := 0; i < n; i++ {
                            h := map[int16]byte{}
                            for j := 0; j < k; j++ {
                                    h[int16(j)] = byte(j)
                            }
                            hs = append(hs, &h)
                    }
                    after = Alloc()
                    fullPerMap := float64(after-before) / float64(n)
                    fmt.Printf("Bytes used for %d maps with %d entries: %d, bytes/map %.1f\n", n, k, after-before, fullPerMap)
                    fmt.Printf("Bytes per entry %.1f\n", (fullPerMap-emptyPerMap)/float64(k))
                    k *= 2
            }
    
    }
    

    Output

    jnml@fsc-r630:~/src/tmp$ go build && ./tmp && go version && uname -a
    Bytes used for 1000 empty maps: 146816, bytes/map 146.8
    Bytes used for 1000 maps with 1 entries: 147040, bytes/map 147.0
    Bytes per entry 0.2
    Bytes used for 1000 maps with 2 entries: 147040, bytes/map 147.0
    Bytes per entry 0.1
    Bytes used for 1000 maps with 4 entries: 247136, bytes/map 247.1
    Bytes per entry 25.1
    Bytes used for 1000 maps with 8 entries: 439056, bytes/map 439.1
    Bytes per entry 36.5
    Bytes used for 1000 maps with 16 entries: 818688, bytes/map 818.7
    Bytes per entry 42.0
    Bytes used for 1000 maps with 32 entries: 1194688, bytes/map 1194.7
    Bytes per entry 32.7
    Bytes used for 1000 maps with 64 entries: 2102976, bytes/map 2103.0
    Bytes per entry 30.6
    Bytes used for 1000 maps with 128 entries: 4155072, bytes/map 4155.1
    Bytes per entry 31.3
    Bytes used for 1000 maps with 256 entries: 6698688, bytes/map 6698.7
    Bytes per entry 25.6
    Bytes used for 1000 maps with 512 entries: 14142976, bytes/map 14143.0
    Bytes per entry 27.3
    Bytes used for 1000 maps with 1024 entries: 51349184, bytes/map 51349.2
    Bytes per entry 50.0
    Bytes used for 1000 maps with 2048 entries: 102467264, bytes/map 102467.3
    Bytes per entry 50.0
    Bytes used for 1000 maps with 4096 entries: 157214816, bytes/map 157214.8
    Bytes per entry 38.3
    Bytes used for 1000 maps with 8192 entries: 407031200, bytes/map 407031.2
    Bytes per entry 49.7
    Bytes used for 1000 maps with 16384 entries: 782616864, bytes/map 782616.9
    Bytes per entry 47.8
    go version devel +83b0b94af636 Sat Mar 09 16:25:30 2013 +1100 linux/amd64
    Linux fsc-r630 3.2.0-38-generic #61-Ubuntu SMP Tue Feb 19 12:18:21 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
    jnml@fsc-r630:~/src/tmp$ 
    

    It's nice to see the numbers are better (by a factor of about 4x). The numbers for the release version (1.0.3) are only slightly higher:

    jnml@fsc-r630:~/src/tmp$ go build && ./tmp
    Bytes used for 1000 empty maps: 144192, bytes/map 144.2
    Bytes used for 1000 maps with 1 entries: 144192, bytes/map 144.2
    Bytes per entry 0.0
    Bytes used for 1000 maps with 2 entries: 144192, bytes/map 144.2
    Bytes per entry 0.0
    Bytes used for 1000 maps with 4 entries: 315648, bytes/map 315.6
    Bytes per entry 42.9
    Bytes used for 1000 maps with 8 entries: 436288, bytes/map 436.3
    Bytes per entry 36.5
    Bytes used for 1000 maps with 16 entries: 885824, bytes/map 885.8
    Bytes per entry 46.4
    Bytes used for 1000 maps with 32 entries: 1331264, bytes/map 1331.3
    Bytes per entry 37.1
    Bytes used for 1000 maps with 64 entries: 2292800, bytes/map 2292.8
    Bytes per entry 33.6
    Bytes used for 1000 maps with 128 entries: 4935920, bytes/map 4935.9
    Bytes per entry 37.4
    Bytes used for 1000 maps with 256 entries: 12164160, bytes/map 12164.2
    Bytes per entry 47.0
    Bytes used for 1000 maps with 512 entries: 29887808, bytes/map 29887.8
    Bytes per entry 58.1
    Bytes used for 1000 maps with 1024 entries: 56840768, bytes/map 56840.8
    Bytes per entry 55.4
    Bytes used for 1000 maps with 2048 entries: 108736064, bytes/map 108736.1
    Bytes per entry 53.0
    Bytes used for 1000 maps with 4096 entries: 184368752, bytes/map 184368.8
    Bytes per entry 45.0
    Bytes used for 1000 maps with 8192 entries: 431340576, bytes/map 431340.6
    Bytes per entry 52.6
    Bytes used for 1000 maps with 16384 entries: 815378816, bytes/map 815378.8
    Bytes per entry 49.8
    jnml@fsc-r630:~/src/tmp$
    

提交回复
热议问题