go 生成hash_go基础之map-写在前面(一)

709d2dcc4a8fc996302115d48a1228a5.png

为什么分析map

在计算机编程语言当中,用的最多的数据结构估计就是map。map以他近乎o(1)的查找效率和修改效率让他在大多数场景下都比较受青睐。map的常规的实现方式都是hash+其他数据结构,如java是hash+红黑树,而我现在即将要分析的go的实现方式是hash+链表。我会分析map的几乎每段代码,并且在我的GitHub可以查看到我的分析,注释十分详尽,欢迎批评指正。我的打算是把一些常用的数据结构都分析一遍,如果有志同道合的人,可以联系我。

我的环境

为了给那些感兴趣看源码分析我的博客的同学阅读得更加清晰,列举了我的环境: 1. go1.14.7 amd64; 2. windows和mac接口,linux没有测试,估计没问题 ; 3. goland,目前最好的golang ide,虽然笔者用起来感觉还是不太完美; 4. 着重分析map[string]string,其他类型的源码变化不大

本篇重点

1.go的map和java的map有区别,go中是一个关键字,而java确实可以直接查看源码,那么如何分析go的map源码? 2.调试过程当中,go充斥着大量指针,如何知道指针指向的内容?map的最小单位bmap除了查看tophash,怎么查看里面的其他隐藏字段? 3.go的map源码为何给不同的key的类型设计不同的实现? 4.其他一些查看源码的小技巧:内存对齐、指针偏移、类型大小等等

如何找到map对应的源码

go的map的结构体是hmap,代码位于runtime/map.go,当编译器编译你申明使用map的源码时候,其实是使用了runtime/map*.go,后面对map的增删改查都是执行该代码,故要弄懂map的底层原理只需要分析该源码,也可以断点调试。 我下面有个自己测试的源码,注意我编译之后查看,就可以发现端倪:

package main

import "fmt"

func main() {
    m1 := make(map[string]string)
    fmt.Println(m1)
    m2 := make(map[string]string, 8)
    fmt.Println(m2)
    m3 := make(map[string]string, 9)
    fmt.Println(m3)
    m4 := map[string]string{}
    fmt.Println(m4)
    m3["1"] = "2"
    for k, v := range m3 {
        fmt.Println(k)
        fmt.Println(v)
    }
    v1 := m3["1"]
    fmt.Println(v1)
    if v2, ok := m3["1"]; ok {
        fmt.Println(v2)
    }
}

上面代码有几种不同申明map的方式,对应runtime/map.go也不同。还有赋值和遍历查找的代码。 下面编译得到汇编指令文件,执行

go tool compile -N -l -S main.go > main.txt

生成了汇编指令文件:

"".main STEXT size=1891 args=0x0 locals=0x288
    0x0000 00000 (main.go:5)    TEXT    "".main(SB), ABIInternal, $648-0
    0x0000 00000 (main.go:5)    MOVQ    TLS, CX
    0x0009 00009 (main.go:5)    PCDATA  $0, $-2
    0x0009 00009 (main.go:5)    MOVQ    (CX)(TLS*2), CX
    0x0010 00016 (main.go:5)    PCDATA  $0, $-1
    0x0010 00016 (main.go:5)    LEAQ    -520(SP), AX
    0x0018 00024 (main.go:5)    CMPQ    AX, 16(CX)
    0x001c 00028 (main.go:5)    PCDATA  $0, $-2
    0x001c 00028 (main.go:5)    JLS 1881
    0x0022 00034 (main.go:5)    PCDATA  $0, $-1
    0x0022 00034 (main.go:5)    SUBQ    $648, SP
    0x0029 00041 (main.go:5)    MOVQ    BP, 640(SP)
    0x0031 00049 (main.go:5)    LEAQ    640(SP), BP
    0x0039 00057 (main.go:5)    PCDATA  $0, $-2
    0x0039 00057 (main.go:5)    PCDATA  $1, $-2
    0x0039 00057 (main.go:5)    FUNCDATA    $0, gclocals·ad6397d3d33bbb6a31b1320349e23274(SB)
    0x0039 00057 (main.go:5)    FUNCDATA    $1, gclocals·1bbf1965a34fa71a63e073b1cf2d752a(SB)
    0x0039 00057 (main.go:5)    FUNCDATA    $2, gclocals·658035074399f748be6dd39603d5113c(SB)
    0x0039 00057 (main.go:5)    FUNCDATA    $3, "".main.stkobj(SB)
    0x0039 00057 (main.go:6)    PCDATA  $0, $0
    0x0039 00057 (main.go:6)    PCDATA  $1, $0
    0x0039 00057 (main.go:6)    CALL    runtime.makemap_small(SB)
    0x003e 00062 (main.go:6)    PCDATA  $0, $1
    0x003e 00062 (main.go:6)    MOVQ    (SP), AX
    0x0042 00066 (main.go:6)    MOVQ    AX, "".m1+80(SP)
    0x0047 00071 (main.go:7)    PCDATA  $0, $0
    0x0047 00071 (main.go:7)    PCDATA  $1, $1
    0x0047 00071 (main.go:7)    MOVQ    AX, ""..autotmp_10+200(SP)
    0x004f 00079 (main.go:7)    PCDATA  $1, $2
    0x004f 00079 (main.go:7)    XORPS   X0, X0
    0x0052 00082 (main.go:7)    MOVUPS  X0, ""..autotmp_9+272(SP)
    0x005a 00090 (main.go:7)    PCDATA  $0, $1
    0x005a 00090 (main.go:7)    PCDATA  $1, $1
    0x005a 00090 (main.go:7)    LEAQ    ""..autotmp_9+272(SP), AX
    0x0062 00098 (main.go:7)    MOVQ    AX, ""..autotmp_15+192(SP)
    0x006a 00106 (main.go:7)    TESTB   AL, (AX)
    0x006c 00108 (main.go:7)    PCDATA  $0, $2
    0x006c 00108 (main.go:7)    PCDATA  $1, $0
    0x006c 00108 (main.go:7)    MOVQ    ""..autotmp_10+200(SP), CX
    0x0074 00116 (main.go:7)    PCDATA  $0, $3
    0x0074 00116 (main.go:7)    LEAQ    type.map[string]string(SB), DX
    0x007b 00123 (main.go:7)    PCDATA  $0, $2
    0x007b 00123 (main.go:7)    MOVQ    DX, ""..autotmp_9+272(SP)
    0x0083 00131 (main.go:7)    PCDATA  $0, $1
    0x0083 00131 (main.go:7)    MOVQ    CX, ""..autotmp_9+280(SP)
    0x008b 00139 (main.go:7)    TESTB   AL, (AX)
    0x008d 00141 (main.go:7)    JMP 143
    0x008f 00143 (main.go:7)    MOVQ    AX, ""..autotmp_14+520(SP)
    0x0097 00151 (main.go:7)    MOVQ    $1, ""..autotmp_14+528(SP)
    0x00a3 00163 (main.go:7)    MOVQ    $1, ""..autotmp_14+536(SP)
    0x00af 00175 (main.go:7)    PCDATA  $0, $0
    0x00af 00175 (main.go:7)    MOVQ    AX, (SP)
    0x00b3 00179 (main.go:7)    MOVQ    $1, 8(SP)
    0x00bc 00188 (main.go:7)    MOVQ    $1, 16(SP)
    0x00c5 00197 (main.go:7)    CALL    fmt.Println(SB)
    0x00ca 00202 (main.go:8)    CALL    runtime.makemap_small(SB)
    0x00cf 00207 (main.go:8)    PCDATA  $0, $1
    0x00cf 00207 (main.go:8)    MOVQ    (SP), AX
    0x00d3 00211 (main.go:8)    MOVQ    AX, "".m2+72(SP)
    0x00d8 00216 (main.go:9)    PCDATA  $0, $0
    0x00d8 00216 (main.go:9)    PCDATA  $1, $1
    0x00d8 00216 (main.go:9)    MOVQ    AX, ""..autotmp_10+200(SP)
    0x00e0 00224 (main.go:9)    PCDATA  $1, $2
    0x00e0 00224 (main.go:9)    XORPS   X0, X0
    0x00e3 00227 (main.go:9)    MOVUPS  X0, ""..autotmp_9+272(SP)
    0x00eb 00235 (main.go:9)    PCDATA  $0, $1
    0x00eb 00235 (main.go:9)    PCDATA  $1, $1
    0x00eb 00235 (main.go:9)    LEAQ    ""..autotmp_9+272(SP), AX
    0x00f3 00243 (main.go:9)    MOVQ    AX, ""..autotmp_17+184(SP)
    0x00fb 00251 (main.go:9)    TESTB   AL, (AX)
    0x00fd 00253 (main.go:9)    PCDATA  $0, $2
    0x00fd 00253 (main.go:9)    PCDATA  $1, $0
    0x00fd 00253 (main.go:9)    MOVQ    ""..autotmp_10+200(SP), CX
    0x0105 00261 (main.go:9)    PCDATA  $0, $3
    0x0105 00261 (main.go:9)    LEAQ    type.map[string]string(SB), DX
    0x010c 00268 (main.go:9)    PCDATA  $0, $2
    0x010c 00268 (main.go:9)    MOVQ    DX, ""..autotmp_9+272(SP)
    0x0114 00276 (main.go:9)    PCDATA  $0, $1
    0x0114 00276 (main.go:9)    MOVQ    CX, ""..autotmp_9+280(SP)
    0x011c 00284 (main.go:9)    TESTB   AL, (AX)
    0x011e 00286 (main.go:9)    JMP 288
    0x0120 00288 (main.go:9)    MOVQ    AX, ""..autotmp_16+496(SP)
    0x0128 00296 (main.go:9)    MOVQ    $1, ""..autotmp_16+504(SP)
    0x0134 00308 (main.go:9)    MOVQ    $1, ""..autotmp_16+512(SP)
    0x0140 00320 (main.go:9)    PCDATA  $0, $0
    0x0140 00320 (main.go:9)    MOVQ    AX, (SP)
    0x0144 00324 (main.go:9)    MOVQ    $1, 8(SP)
    0x014d 00333 (main.go:9)    MOVQ    $1, 16(SP)
    0x0156 00342 (main.go:9)    CALL    fmt.Println(SB)
    0x015b 00347 (main.go:10)   PCDATA  $0, $1
    0x015b 00347 (main.go:10)   LEAQ    type.map[string]string(SB), AX
    0x0162 00354 (main.go:10)   PCDATA  $0, $0
    0x0162 00354 (main.go:10)   MOVQ    AX, (SP)
    0x0166 00358 (main.go:10)   MOVQ    $9, 8(SP)
    0x016f 00367 (main.go:10)   MOVQ    $0, 16(SP)
    0x0178 00376 (main.go:10)   CALL    runtime.makemap(SB)
    0x017d 00381 (main.go:10)   PCDATA  $0, $1
    0x017d 00381 (main.go:10)   MOVQ    24(SP), AX
    0x0182 00386 (main.go:10)   PCDATA  $1, $3
    0x0182 00386 (main.go:10)   MOVQ    AX, "".m3+64(SP)
    0x0187 00391 (main.go:11)   PCDATA  $0, $0
    0x0187 00391 (main.go:11)   PCDATA  $1, $4
    0x0187 00391 (main.go:11)   MOVQ    AX, ""..autotmp_10+200(SP)
    0x018f 00399 (main.go:11)   PCDATA  $1, $5
    0x018f 00399 (main.go:11)   XORPS   X0, X0
    0x0192 00402 (main.go:11)   MOVUPS  X0, ""..autotmp_9+272(SP)
    0x019a 00410 (main.go:11)   PCDATA  $0, $1
    0x019a 00410 (main.go:11)   PCDATA  $1, $4
    0x019a 00410 (main.go:11)   LEAQ    ""..autotmp_9+272(SP), AX
    0x01a2 00418 (main.go:11)   MOVQ    AX, ""..autotmp_19+176(SP)
    0x01aa 00426 (main.go:11)   TESTB   AL, (AX)
    0x01ac 00428 (main.go:11)   PCDATA  $0, $2
    0x01ac 00428 (main.go:11)   PCDATA  $1, $3
    0x01ac 00428 (main.go:11)   MOVQ    ""..autotmp_10+200(SP), CX
    0x01b4 00436 (main.go:11)   PCDATA  $0, $3
    0x01b4 00436 (main.go:11)   LEAQ    type.map[string]string(SB), DX
    0x01bb 00443 (main.go:11)   PCDATA  $0, $2
    0x01bb 00443 (main.go:11)   MOVQ    DX, ""..autotmp_9+272(SP)
    0x01c3 00451 (main.go:11)   PCDATA  $0, $1
    0x01c3 00451 (main.go:11)   MOVQ    CX, ""..autotmp_9+280(SP)
    0x01cb 00459 (main.go:11)   TESTB   AL, (AX)
    0x01cd 00461 (main.go:11)   JMP 463
    0x01cf 00463 (main.go:11)   MOVQ    AX, ""..autotmp_18+472(SP)
    0x01d7 00471 (main.go:11)   MOVQ    $1, ""..autotmp_18+480(SP)
    0x01e3 00483 (main.go:11)   MOVQ    $1, ""..autotmp_18+488(SP)
    0x01ef 00495 (main.go:11)   PCDATA  $0, $0
    0x01ef 00495 (main.go:11)   MOVQ    AX, (SP)
    0x01f3 00499 (main.go:11)   MOVQ    $1, 8(SP)
    0x01fc 00508 (main.go:11)   MOVQ    $1, 16(SP)
    0x0205 00517 (main.go:11)   CALL    fmt.Println(SB)
    0x020a 00522 (main.go:12)   CALL    runtime.makemap_small(SB)
    0x020f 00527 (main.go:12)   PCDATA  $0, $1
    0x020f 00527 (main.go:12)   MOVQ    (SP), AX
    0x0213 00531 (main.go:12)   PCDATA  $0, $0
    0x0213 00531 (main.go:12)   PCDATA  $1, $6
    0x0213 00531 (main.go:12)   MOVQ    AX, "".m4+56(SP)
    0x0218 00536 (main.go:13)   PCDATA  $0, $1
    0x0218 00536 (main.go:13)   PCDATA  $1, $3
    0x0218 00536 (main.go:13)   MOVQ    "".m4+56(SP), AX
    0x021d 00541 (main.go:13)   PCDATA  $0, $0
    0x021d 00541 (main.go:13)   PCDATA  $1, $4
    0x021d 00541 (main.go:13)   MOVQ    AX, ""..autotmp_10+200(SP)
    0x0225 00549 (main.go:13)   PCDATA  $1, $5
    0x0225 00549 (main.go:13)   XORPS   X0, X0
    0x0228 00552 (main.go:13)   MOVUPS  X0, ""..autotmp_9+272(SP)
    0x0230 00560 (main.go:13)   PCDATA  $0, $1
    0x0230 00560 (main.go:13)   PCDATA  $1, $4
    0x0230 00560 (main.go:13)   LEAQ    ""..autotmp_9+272(SP), AX
    0x0238 00568 (main.go:13)   MOVQ    AX, ""..autotmp_23+168(SP)
    0x0240 00576 (main.go:13)   TESTB   AL, (AX)
    0x0242 00578 (main.go:13)   PCDATA  $0, $2
    0x0242 00578 (main.go:13)   PCDATA  $1, $3
    0x0242 00578 (main.go:13)   MOVQ    ""..autotmp_10+200(SP), CX
    0x024a 00586 (main.go:13)   PCDATA  $0, $3
    0x024a 00586 (main.go:13)   LEAQ    type.map[string]string(SB), DX
    0x0251 00593 (main.go:13)   PCDATA  $0, $2
    0x0251 00593 (main.go:13)   MOVQ    DX, ""..autotmp_9+272(SP)
    0x0259 00601 (main.go:13)   PCDATA  $0, $1
    0x0259 00601 (main.go:13)   MOVQ    CX, ""..autotmp_9+280(SP)
    0x0261 00609 (main.go:13)   TESTB   AL, (AX)
    0x0263 00611 (main.go:13)   JMP 613
    0x0265 00613 (main.go:13)   MOVQ    AX, ""..autotmp_22+448(SP)
    0x026d 00621 (main.go:13)   MOVQ    $1, ""..autotmp_22+456(SP)
    0x0279 00633 (main.go:13)   MOVQ    $1, ""..autotmp_22+464(SP)
    0x0285 00645 (main.go:13)   PCDATA  $0, $0
    0x0285 00645 (main.go:13)   MOVQ    AX, (SP)
    0x0289 00649 (main.go:13)   MOVQ    $1, 8(SP)
    0x0292 00658 (main.go:13)   MOVQ    $1, 16(SP)
    0x029b 00667 (main.go:13)   CALL    fmt.Println(SB)
    0x02a0 00672 (main.go:14)   PCDATA  $0, $1
    0x02a0 00672 (main.go:14)   LEAQ    type.map[string]string(SB), AX
    0x02a7 00679 (main.go:14)   PCDATA  $0, $0
    0x02a7 00679 (main.go:14)   MOVQ    AX, (SP)
    0x02ab 00683 (main.go:14)   PCDATA  $0, $1
    0x02ab 00683 (main.go:14)   MOVQ    "".m3+64(SP), AX
    0x02b0 00688 (main.go:14)   PCDATA  $0, $0
    0x02b0 00688 (main.go:14)   MOVQ    AX, 8(SP)
    0x02b5 00693 (main.go:14)   PCDATA  $0, $1
    0x02b5 00693 (main.go:14)   LEAQ    go.string."1"(SB), AX
    0x02bc 00700 (main.go:14)   PCDATA  $0, $0
    0x02bc 00700 (main.go:14)   MOVQ    AX, 16(SP)
    0x02c1 00705 (main.go:14)   MOVQ    $1, 24(SP)
    0x02ca 00714 (main.go:14)   CALL    runtime.mapassign_faststr(SB)
    0x02cf 00719 (main.go:14)   PCDATA  $0, $4
    0x02cf 00719 (main.go:14)   MOVQ    32(SP), DI
    0x02d4 00724 (main.go:14)   MOVQ    DI, ""..autotmp_24+160(SP)
    0x02dc 00732 (main.go:14)   TESTB   AL, (DI)
    0x02de 00734 (main.go:14)   MOVQ    $1, 8(DI)
    0x02e6 00742 (main.go:14)   PCDATA  $0, $-2
    0x02e6 00742 (main.go:14)   PCDATA  $1, $-2
    0x02e6 00742 (main.go:14)   CMPL    runtime.writeBarrier(SB), $0
    0x02ed 00749 (main.go:14)   JEQ 756
    0x02ef 00751 (main.go:14)   JMP 1864
    0x02f4 00756 (main.go:14)   LEAQ    go.string."2"(SB), AX
    0x02fb 00763 (main.go:14)   MOVQ    AX, (DI)
    0x02fe 00766 (main.go:14)   JMP 768
    0x0300 00768 (main.go:15)   PCDATA  $0, $1
    0x0300 00768 (main.go:15)   PCDATA  $1, $3
    0x0300 00768 (main.go:15)   MOVQ    "".m3+64(SP), AX
    0x0305 00773 (main.go:15)   PCDATA  $0, $0
    0x0305 00773 (main.go:15)   PCDATA  $1, $4
    0x0305 00773 (main.go:15)   MOVQ    AX, ""..autotmp_10+200(SP)
    0x030d 00781 (main.go:15)   PCDATA  $0, $4
    0x030d 00781 (main.go:15)   PCDATA  $1, $7
    0x030d 00781 (main.go:15)   LEAQ    ""..autotmp_11+544(SP), DI
    0x0315 00789 (main.go:15)   XORPS   X0, X0
    0x0318 00792 (main.go:15)   PCDATA  $0, $0
    0x0318 00792 (main.go:15)   LEAQ    -32(DI), DI
    0x031c 00796 (main.go:15)   DUFFZERO    $273
    0x032f 00815 (main.go:15)   PCDATA  $0, $1
    0x032f 00815 (main.go:15)   LEAQ    type.map[string]string(SB), AX
    0x0336 00822 (main.go:15)   PCDATA  $0, $0
    0x0336 00822 (main.go:15)   MOVQ    AX, (SP)
    0x033a 00826 (main.go:15)   PCDATA  $0, $1
    0x033a 00826 (main.go:15)   PCDATA  $1, $8
    0x033a 00826 (main.go:15)   MOVQ    ""..autotmp_10+200(SP), AX
    0x0342 00834 (main.go:15)   PCDATA  $0, $0
    0x0342 00834 (main.go:15)   MOVQ    AX, 8(SP)
    0x0347 00839 (main.go:15)   PCDATA  $0, $1
    0x0347 00839 (main.go:15)   LEAQ    ""..autotmp_11+544(SP), AX
    0x034f 00847 (main.go:15)   PCDATA  $0, $0
    0x034f 00847 (main.go:15)   MOVQ    AX, 16(SP)
    0x0354 00852 (main.go:15)   CALL    runtime.mapiterinit(SB)
    0x0359 00857 (main.go:15)   JMP 859
    0x035b 00859 (main.go:15)   CMPQ    ""..autotmp_11+544(SP), $0
    0x0364 00868 (main.go:15)   JNE 875
    0x0366 00870 (main.go:15)   JMP 1329
    0x036b 00875 (main.go:15)   PCDATA  $0, $1
    0x036b 00875 (main.go:15)   MOVQ    ""..autotmp_11+552(SP), AX
    0x0373 00883 (main.go:15)   TESTB   AL, (AX)
    0x0375 00885 (main.go:15)   MOVQ    8(AX), CX
    0x0379 00889 (main.go:15)   MOVQ    (AX), AX
    0x037c 00892 (main.go:15)   PCDATA  $0, $0
    0x037c 00892 (main.go:15)   PCDATA  $1, $9
    0x037c 00892 (main.go:15)   MOVQ    AX, ""..autotmp_25+288(SP)
    0x0384 00900 (main.go:15)   MOVQ    CX, ""..autotmp_25+296(SP)
    0x038c 00908 (main.go:15)   PCDATA  $0, $1
    0x038c 00908 (main.go:15)   MOVQ    ""..autotmp_11+544(SP), AX
    0x0394 00916 (main.go:15)   TESTB   AL, (AX)
    0x0396 00918 (main.go:15)   MOVQ    8(AX), CX
    0x039a 00922 (main.go:15)   MOVQ    (AX), AX
    0x039d 00925 (main.go:15)   PCDATA  $0, $0
    0x039d 00925 (main.go:15)   PCDATA  $1, $10
    0x039d 00925 (main.go:15)   MOVQ    AX, "".k+256(SP)
    0x03a5 00933 (main.go:15)   MOVQ    CX, "".k+264(SP)
    0x03ad 00941 (main.go:15)   MOVQ    ""..autotmp_25+296(SP), AX
    0x03b5 00949 (main.go:15)   PCDATA  $0, $5
    0x03b5 00949 (main.go:15)   PCDATA  $1, $11
    0x03b5 00949 (main.go:15)   MOVQ    ""..autotmp_25+288(SP), CX
    0x03bd 00957 (main.go:15)   PCDATA  $0, $0
    0x03bd 00957 (main.go:15)   PCDATA  $1, $12
    0x03bd 00957 (main.go:15)   MOVQ    CX, "".v+240(SP)
    0x03c5 00965 (main.go:15)   MOVQ    AX, "".v+248(SP)
    0x03cd 00973 (main.go:16)   MOVQ    "".k+264(SP), AX
    0x03d5 00981 (main.go:16)   PCDATA  $0, $5
    0x03d5 00981 (main.go:16)   PCDATA  $1, $13
    0x03d5 00981 (main.go:16)   MOVQ    "".k+256(SP), CX
    0x03dd 00989 (main.go:16)   PCDATA  $0, $0
    0x03dd 00989 (main.go:16)   MOVQ    CX, (SP)
    0x03e1 00993 (main.go:16)   MOVQ    AX, 8(SP)
    0x03e6 00998 (main.go:16)   CALL    runtime.convTstring(SB)
    0x03eb 01003 (main.go:16)   PCDATA  $0, $1
    0x03eb 01003 (main.go:16)   MOVQ    16(SP), AX
    0x03f0 01008 (main.go:16)   PCDATA  $0, $0
    0x03f0 01008 (main.go:16)   PCDATA  $1, $14
    0x03f0 01008 (main.go:16)   MOVQ    AX, ""..autotmp_26+152(SP)
    0x03f8 01016 (main.go:16)   PCDATA  $1, $15
    0x03f8 01016 (main.go:16)   XORPS   X0, X0
    0x03fb 01019 (main.go:16)   MOVUPS  X0, ""..autotmp_9+272(SP)
    0x0403 01027 (main.go:16)   PCDATA  $0, $1
    0x0403 01027 (main.go:16)   PCDATA  $1, $14
    0x0403 01027 (main.go:16)   LEAQ    ""..autotmp_9+272(SP), AX
    0x040b 01035 (main.go:16)   MOVQ    AX, ""..autotmp_28+144(SP)
    0x0413 01043 (main.go:16)   TESTB   AL, (AX)
    0x0415 01045 (main.go:16)   PCDATA  $0, $2
    0x0415 01045 (main.go:16)   PCDATA  $1, $13
    0x0415 01045 (main.go:16)   MOVQ    ""..autotmp_26+152(SP), CX
    0x041d 01053 (main.go:16)   PCDATA  $0, $3
    0x041d 01053 (main.go:16)   LEAQ    type.string(SB), DX
    0x0424 01060 (main.go:16)   PCDATA  $0, $2
    0x0424 01060 (main.go:16)   MOVQ    DX, ""..autotmp_9+272(SP)
    0x042c 01068 (main.go:16)   PCDATA  $0, $1
    0x042c 01068 (main.go:16)   MOVQ    CX, ""..autotmp_9+280(SP)
    0x0434 01076 (main.go:16)   TESTB   AL, (AX)
    0x0436 01078 (main.go:16)   JMP 1080
    0x0438 01080 (main.go:16)   MOVQ    AX, ""..autotmp_27+424(SP)
    0x0440 01088 (main.go:16)   MOVQ    $1, ""..autotmp_27+432(SP)
    0x044c 01100 (main.go:16)   MOVQ    $1, ""..autotmp_27+440(SP)
    0x0458 01112 (main.go:16)   PCDATA  $0, $0
    0x0458 01112 (main.go:16)   MOVQ    AX, (SP)
    0x045c 01116 (main.go:16)   MOVQ    $1, 8(SP)
    0x0465 01125 (main.go:16)   MOVQ    $1, 16(SP)
    0x046e 01134 (main.go:16)   CALL    fmt.Println(SB)
    0x0473 01139 (main.go:17)   MOVQ    "".v+248(SP), AX
    0x047b 01147 (main.go:17)   PCDATA  $0, $5
    0x047b 01147 (main.go:17)   PCDATA  $1, $8
    0x047b 01147 (main.go:17)   MOVQ    "".v+240(SP), CX
    0x0483 01155 (main.go:17)   PCDATA  $0, $0
    0x0483 01155 (main.go:17)   MOVQ    CX, (SP)
    0x0487 01159 (main.go:17)   MOVQ    AX, 8(SP)
    0x048c 01164 (main.go:17)   CALL    runtime.convTstring(SB)
    0x0491 01169 (main.go:17)   PCDATA  $0, $1
    0x0491 01169 (main.go:17)   MOVQ    16(SP), AX
    0x0496 01174 (main.go:17)   PCDATA  $0, $0
    0x0496 01174 (main.go:17)   PCDATA  $1, $16
    0x0496 01174 (main.go:17)   MOVQ    AX, ""..autotmp_29+136(SP)
    0x049e 01182 (main.go:17)   PCDATA  $1, $17
    0x049e 01182 (main.go:17)   XORPS   X0, X0
    0x04a1 01185 (main.go:17)   MOVUPS  X0, ""..autotmp_9+272(SP)
    0x04a9 01193 (main.go:17)   PCDATA  $0, $1
    0x04a9 01193 (main.go:17)   PCDATA  $1, $16
    0x04a9 01193 (main.go:17)   LEAQ    ""..autotmp_9+272(SP), AX
    0x04b1 01201 (main.go:17)   MOVQ    AX, ""..autotmp_31+128(SP)
    0x04b9 01209 (main.go:17)   TESTB   AL, (AX)
    0x04bb 01211 (main.go:17)   PCDATA  $0, $2
    0x04bb 01211 (main.go:17)   PCDATA  $1, $8
    0x04bb 01211 (main.go:17)   MOVQ    ""..autotmp_29+136(SP), CX
    0x04c3 01219 (main.go:17)   PCDATA  $0, $3
    0x04c3 01219 (main.go:17)   LEAQ    type.string(SB), DX
    0x04ca 01226 (main.go:17)   PCDATA  $0, $2
    0x04ca 01226 (main.go:17)   MOVQ    DX, ""..autotmp_9+272(SP)
    0x04d2 01234 (main.go:17)   PCDATA  $0, $1
    0x04d2 01234 (main.go:17)   MOVQ    CX, ""..autotmp_9+280(SP)
    0x04da 01242 (main.go:17)   TESTB   AL, (AX)
    0x04dc 01244 (main.go:17)   JMP 1246
    0x04de 01246 (main.go:17)   MOVQ    AX, ""..autotmp_30+400(SP)
    0x04e6 01254 (main.go:17)   MOVQ    $1, ""..autotmp_30+408(SP)
    0x04f2 01266 (main.go:17)   MOVQ    $1, ""..autotmp_30+416(SP)
    0x04fe 01278 (main.go:17)   PCDATA  $0, $0
    0x04fe 01278 (main.go:17)   MOVQ    AX, (SP)
    0x0502 01282 (main.go:17)   MOVQ    $1, 8(SP)
    0x050b 01291 (main.go:17)   MOVQ    $1, 16(SP)
    0x0514 01300 (main.go:17)   CALL    fmt.Println(SB)
    0x0519 01305 (main.go:17)   JMP 1307
    0x051b 01307 (main.go:15)   PCDATA  $0, $1
    0x051b 01307 (main.go:15)   LEAQ    ""..autotmp_11+544(SP), AX
    0x0523 01315 (main.go:15)   PCDATA  $0, $0
    0x0523 01315 (main.go:15)   MOVQ    AX, (SP)
    0x0527 01319 (main.go:15)   CALL    runtime.mapiternext(SB)
    0x052c 01324 (main.go:15)   JMP 859
    0x0531 01329 (main.go:19)   PCDATA  $0, $1
    0x0531 01329 (main.go:19)   PCDATA  $1, $3
    0x0531 01329 (main.go:19)   LEAQ    type.map[string]string(SB), AX
    0x0538 01336 (main.go:19)   PCDATA  $0, $0
    0x0538 01336 (main.go:19)   MOVQ    AX, (SP)
    0x053c 01340 (main.go:19)   PCDATA  $0, $1
    0x053c 01340 (main.go:19)   MOVQ    "".m3+64(SP), AX
    0x0541 01345 (main.go:19)   PCDATA  $0, $0
    0x0541 01345 (main.go:19)   MOVQ    AX, 8(SP)
    0x0546 01350 (main.go:19)   PCDATA  $0, $1
    0x0546 01350 (main.go:19)   LEAQ    go.string."1"(SB), AX
    0x054d 01357 (main.go:19)   PCDATA  $0, $0
    0x054d 01357 (main.go:19)   MOVQ    AX, 16(SP)
    0x0552 01362 (main.go:19)   MOVQ    $1, 24(SP)
    0x055b 01371 (main.go:19)   CALL    runtime.mapaccess1_faststr(SB)
    0x0560 01376 (main.go:19)   PCDATA  $0, $1
    0x0560 01376 (main.go:19)   MOVQ    32(SP), AX
    0x0565 01381 (main.go:19)   PCDATA  $0, $2
    0x0565 01381 (main.go:19)   MOVQ    (AX), CX
    0x0568 01384 (main.go:19)   PCDATA  $0, $5
    0x0568 01384 (main.go:19)   MOVQ    8(AX), AX
    0x056c 01388 (main.go:19)   MOVQ    CX, "".v1+224(SP)
    0x0574 01396 (main.go:19)   MOVQ    AX, "".v1+232(SP)
    0x057c 01404 (main.go:20)   PCDATA  $0, $0
    0x057c 01404 (main.go:20)   MOVQ    CX, (SP)
    0x0580 01408 (main.go:20)   MOVQ    AX, 8(SP)
    0x0585 01413 (main.go:20)   CALL    runtime.convTstring(SB)
    0x058a 01418 (main.go:20)   PCDATA  $0, $1
    0x058a 01418 (main.go:20)   MOVQ    16(SP), AX
    0x058f 01423 (main.go:20)   PCDATA  $0, $0
    0x058f 01423 (main.go:20)   PCDATA  $1, $18
    0x058f 01423 (main.go:20)   MOVQ    AX, ""..autotmp_32+120(SP)
    0x0594 01428 (main.go:20)   PCDATA  $1, $19
    0x0594 01428 (main.go:20)   XORPS   X0, X0
    0x0597 01431 (main.go:20)   MOVUPS  X0, ""..autotmp_9+272(SP)
    0x059f 01439 (main.go:20)   PCDATA  $0, $1
    0x059f 01439 (main.go:20)   PCDATA  $1, $18
    0x059f 01439 (main.go:20)   LEAQ    ""..autotmp_9+272(SP), AX
    0x05a7 01447 (main.go:20)   MOVQ    AX, ""..autotmp_34+112(SP)
    0x05ac 01452 (main.go:20)   TESTB   AL, (AX)
    0x05ae 01454 (main.go:20)   PCDATA  $0, $2
    0x05ae 01454 (main.go:20)   PCDATA  $1, $3
    0x05ae 01454 (main.go:20)   MOVQ    ""..autotmp_32+120(SP), CX
    0x05b3 01459 (main.go:20)   PCDATA  $0, $3
    0x05b3 01459 (main.go:20)   LEAQ    type.string(SB), DX
    0x05ba 01466 (main.go:20)   PCDATA  $0, $2
    0x05ba 01466 (main.go:20)   MOVQ    DX, ""..autotmp_9+272(SP)
    0x05c2 01474 (main.go:20)   PCDATA  $0, $1
    0x05c2 01474 (main.go:20)   MOVQ    CX, ""..autotmp_9+280(SP)
    0x05ca 01482 (main.go:20)   TESTB   AL, (AX)
    0x05cc 01484 (main.go:20)   JMP 1486
    0x05ce 01486 (main.go:20)   MOVQ    AX, ""..autotmp_33+376(SP)
    0x05d6 01494 (main.go:20)   MOVQ    $1, ""..autotmp_33+384(SP)
    0x05e2 01506 (main.go:20)   MOVQ    $1, ""..autotmp_33+392(SP)
    0x05ee 01518 (main.go:20)   PCDATA  $0, $0
    0x05ee 01518 (main.go:20)   MOVQ    AX, (SP)
    0x05f2 01522 (main.go:20)   MOVQ    $1, 8(SP)
    0x05fb 01531 (main.go:20)   MOVQ    $1, 16(SP)
    0x0604 01540 (main.go:20)   CALL    fmt.Println(SB)
    0x0609 01545 (main.go:21)   XORPS   X0, X0
    0x060c 01548 (main.go:21)   MOVUPS  X0, ""..autotmp_12+336(SP)
    0x0614 01556 (main.go:21)   PCDATA  $0, $1
    0x0614 01556 (main.go:21)   LEAQ    type.map[string]string(SB), AX
    0x061b 01563 (main.go:21)   PCDATA  $0, $0
    0x061b 01563 (main.go:21)   MOVQ    AX, (SP)
    0x061f 01567 (main.go:21)   PCDATA  $0, $1
    0x061f 01567 (main.go:21)   PCDATA  $1, $0
    0x061f 01567 (main.go:21)   MOVQ    "".m3+64(SP), AX
    0x0624 01572 (main.go:21)   PCDATA  $0, $0
    0x0624 01572 (main.go:21)   MOVQ    AX, 8(SP)
    0x0629 01577 (main.go:21)   PCDATA  $0, $1
    0x0629 01577 (main.go:21)   LEAQ    go.string."1"(SB), AX
    0x0630 01584 (main.go:21)   PCDATA  $0, $0
    0x0630 01584 (main.go:21)   MOVQ    AX, 16(SP)
    0x0635 01589 (main.go:21)   MOVQ    $1, 24(SP)
    0x063e 01598 (main.go:21)   CALL    runtime.mapaccess2_faststr(SB)
    0x0643 01603 (main.go:21)   PCDATA  $0, $1
    0x0643 01603 (main.go:21)   MOVQ    32(SP), AX
    0x0648 01608 (main.go:21)   PCDATA  $0, $0
    0x0648 01608 (main.go:21)   PCDATA  $1, $20
    0x0648 01608 (main.go:21)   MOVQ    AX, ""..autotmp_35+104(SP)
    0x064d 01613 (main.go:21)   MOVBLZX 40(SP), AX
    0x0652 01618 (main.go:21)   MOVB    AL, ""..autotmp_13+55(SP)
    0x0656 01622 (main.go:21)   PCDATA  $0, $1
    0x0656 01622 (main.go:21)   PCDATA  $1, $0
    0x0656 01622 (main.go:21)   MOVQ    ""..autotmp_35+104(SP), AX
    0x065b 01627 (main.go:21)   MOVQ    8(AX), CX
    0x065f 01631 (main.go:21)   MOVQ    (AX), AX
    0x0662 01634 (main.go:21)   MOVQ    AX, ""..autotmp_12+336(SP)
    0x066a 01642 (main.go:21)   MOVQ    CX, ""..autotmp_12+344(SP)
    0x0672 01650 (main.go:21)   PCDATA  $0, $0
    0x0672 01650 (main.go:21)   PCDATA  $1, $21
    0x0672 01650 (main.go:21)   MOVQ    AX, "".v2+208(SP)
    0x067a 01658 (main.go:21)   MOVQ    CX, "".v2+216(SP)
    0x0682 01666 (main.go:21)   MOVBLZX ""..autotmp_13+55(SP), AX
    0x0687 01671 (main.go:21)   MOVB    AL, "".ok+54(SP)
    0x068b 01675 (main.go:21)   CMPB    "".ok+54(SP), $0
    0x0690 01680 (main.go:21)   JNE 1687
    0x0692 01682 (main.go:21)   JMP 1862
    0x0697 01687 (main.go:22)   MOVQ    "".v2+216(SP), AX
    0x069f 01695 (main.go:22)   PCDATA  $0, $5
    0x069f 01695 (main.go:22)   PCDATA  $1, $0
    0x069f 01695 (main.go:22)   MOVQ    "".v2+208(SP), CX
    0x06a7 01703 (main.go:22)   PCDATA  $0, $0
    0x06a7 01703 (main.go:22)   MOVQ    CX, (SP)
    0x06ab 01707 (main.go:22)   MOVQ    AX, 8(SP)
    0x06b0 01712 (main.go:22)   CALL    runtime.convTstring(SB)
    0x06b5 01717 (main.go:22)   PCDATA  $0, $1
    0x06b5 01717 (main.go:22)   MOVQ    16(SP), AX
    0x06ba 01722 (main.go:22)   PCDATA  $0, $0
    0x06ba 01722 (main.go:22)   PCDATA  $1, $22
    0x06ba 01722 (main.go:22)   MOVQ    AX, ""..autotmp_36+96(SP)
    0x06bf 01727 (main.go:22)   PCDATA  $1, $23
    0x06bf 01727 (main.go:22)   XORPS   X0, X0
    0x06c2 01730 (main.go:22)   MOVUPS  X0, ""..autotmp_9+272(SP)
    0x06ca 01738 (main.go:22)   PCDATA  $0, $1
    0x06ca 01738 (main.go:22)   PCDATA  $1, $22
    0x06ca 01738 (main.go:22)   LEAQ    ""..autotmp_9+272(SP), AX
    0x06d2 01746 (main.go:22)   MOVQ    AX, ""..autotmp_38+88(SP)
    0x06d7 01751 (main.go:22)   TESTB   AL, (AX)
    0x06d9 01753 (main.go:22)   PCDATA  $0, $2
    0x06d9 01753 (main.go:22)   PCDATA  $1, $0
    0x06d9 01753 (main.go:22)   MOVQ    ""..autotmp_36+96(SP), CX
    0x06de 01758 (main.go:22)   PCDATA  $0, $3
    0x06de 01758 (main.go:22)   LEAQ    type.string(SB), DX
    0x06e5 01765 (main.go:22)   PCDATA  $0, $2
    0x06e5 01765 (main.go:22)   MOVQ    DX, ""..autotmp_9+272(SP)
    0x06ed 01773 (main.go:22)   PCDATA  $0, $1
    0x06ed 01773 (main.go:22)   MOVQ    CX, ""..autotmp_9+280(SP)
    0x06f5 01781 (main.go:22)   TESTB   AL, (AX)
    0x06f7 01783 (main.go:22)   JMP 1785
    0x06f9 01785 (main.go:22)   MOVQ    AX, ""..autotmp_37+352(SP)
    0x0701 01793 (main.go:22)   MOVQ    $1, ""..autotmp_37+360(SP)
    0x070d 01805 (main.go:22)   MOVQ    $1, ""..autotmp_37+368(SP)
    0x0719 01817 (main.go:22)   PCDATA  $0, $0
    0x0719 01817 (main.go:22)   MOVQ    AX, (SP)
    0x071d 01821 (main.go:22)   MOVQ    $1, 8(SP)
    0x0726 01830 (main.go:22)   MOVQ    $1, 16(SP)
    0x072f 01839 (main.go:22)   CALL    fmt.Println(SB)
    0x0734 01844 (main.go:22)   JMP 1846
    0x0736 01846 (<unknown line number>)    PCDATA  $0, $-1
    0x0736 01846 (<unknown line number>)    PCDATA  $1, $-1
    0x0736 01846 (<unknown line number>)    MOVQ    640(SP), BP
    0x073e 01854 (<unknown line number>)    ADDQ    $648, SP
    0x0745 01861 (<unknown line number>)    RET
    0x0746 01862 (main.go:21)   JMP 1846
    0x0748 01864 (main.go:14)   PCDATA  $0, $-2
    0x0748 01864 (main.go:14)   PCDATA  $1, $-2
    0x0748 01864 (main.go:14)   LEAQ    go.string."2"(SB), AX
    0x074f 01871 (main.go:14)   CALL    runtime.gcWriteBarrier(SB)
    0x0754 01876 (main.go:14)   JMP 768
    0x0759 01881 (main.go:14)   NOP
    0x0759 01881 (main.go:5)    PCDATA  $1, $-1
    0x0759 01881 (main.go:5)    PCDATA  $0, $-2
    0x0759 01881 (main.go:5)    CALL    runtime.morestack_noctxt(SB)
    0x075e 01886 (main.go:5)    PCDATA  $0, $-1
    0x075e 01886 (main.go:5)    JMP 0

东西有点多,但是我们只分析几个重点 - main.go的第6行、第8行和第12行的map申明分别对应着main.txt23行、57行和132行,都是调用的runtime.makemap_small方法 - main.go的第10行对应着main.txt的97行runtime.makemap方法 - main.go的第14行的赋值对应着main.txt的184行runtime.mapassign_faststr方法 - main.go的第15行的循环对应着main.txt第224行的runtime.mapiterinit方法初始化得到迭代器 - main.go的第19行和第21行分别对着main.txt2个不同的方法runtime.mapaccess1_faststr和runtime.mapaccess2_faststr

runtime/map.go的方法包括上面列举的方法:runtime.makemap_small、runtime.makemap和runtime.mapiterinit方法

3b9a24e17f95e9e14eb4762c06bd864d.png

由于我的示例代码的map的key是string类型,故runtime.mapassign_faststr、runtime.mapaccess1_faststr和runtime.mapaccess2_faststr方法在runtime/map_faststr.go代码里面,该文件优化了string类型的key的操作:

2dedd5b6840803bd66027c4a607cecb4.png

go的map对应的结构体hmap

go的map的基础结构体是hmap,在runtime/map.go中,

// A header for a Go map.
type hmap struct {
    // Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.
    // Make sure this stays in sync with the compiler's definition.
    // map存储的键值对个数
    count     int // # live cells == size of map.  Must be first (used by len() builtin)
    // 表示map的一些标志位
    flags     uint8
    // map的桶的2的对数就是B值
    B         uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
    // 溢出桶个数,是个近似数,不完全相等
    noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
    // hash种子
    hash0     uint32 // hash seed

    // 桶,真正存数据的地方,2^B个桶
    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
    // 从oldbuckets迁移到新的buckets的进度
    nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)

    // 当key不是指针类型的数据的时候,里面会存溢出桶,这样会避免go的扫描
    extra *mapextra // optional fields
}

既然是map结构体,为何注释说是一个header呢?这是因为buckets和oldbuckets这2个字段并没有真正存取数据,只是存了一个指针,指向存取buckets的地址,故我们在使用过程中拷贝hmap的时候,并没有真正拷贝map的数据,只是拷贝了hmap这个结构体的一些数据。 在看看hmap的字段mapextra:

// mapextra holds fields that are not present on all maps.
type mapextra struct {
    // If both key and elem do not contain pointers and are inline, then we mark bucket
    // 如果key和value都不包括指针并且内敛,然后我们就标记bucket没有指针
    // type as containing no pointers. This avoids scanning such maps.
    // 这样会避免gc扫描
    // However, bmap.overflow is a pointer. In order to keep overflow buckets
    // 但是,虽然key和value不包括指针,但是逸出桶却是个指针,为了让逸出桶一直
    // alive, we store pointers to all overflow buckets in hmap.extra.overflow and hmap.extra.oldoverflow.
    // 存在,所以就把逸出桶和需要迁移的逸出桶的指针存到hamp的extra字段里面
    // overflow and oldoverflow are only used if key and elem do not contain pointers.
    // 如果key和elme包含指针,overflow和oldoverflow就不会被使用了
    // overflow contains overflow buckets for hmap.buckets.
    // oldoverflow contains overflow buckets for hmap.oldbuckets.
    // The indirection allows to store a pointer to the slice in hiter.
    overflow    *[]*bmap
    oldoverflow *[]*bmap

    // nextOverflow holds a pointer to a free overflow bucket.
    nextOverflow *bmap
}

如mapextra结构体为啥说有些字段并不会在所有map里面全部都有呢?mapextra是一个为了优化bucket而设计的,当key或value是指针的时候,此时overflow和oldoverflow就不会被使用,只有nextOverflow会被使用,该字段保存了预先申请的逸出桶,在没有发生扩容的时候,而一个桶或者说bmap的8个tophash都被使用完了,那么就要考虑使用逸出桶。 当key和value都没有指针的时候bucket的bmap的_type的ptrdata就是0,意味着该结构体是没有指针的,申请bmap内存的时候,会申请一个没有指针的span,这样会避免gc扫描该内存,会提高效率,但是bmap的最后一个内存块是确确实实存放指针的,所以用uintptr存储着该map的逸出桶的地址,但是由于没有指向下一个逸出桶,可能会被gc回收掉,所以就需要overflow存取指向该逸出桶的指针避免被gc回收掉。 overflow和oldoverflow的用处差不多,只是oldoverflow为了迁移使用,后面的系列会详说。

bucket的结构体bmap

bmap就是真正存数据的结构体了,bmap在源码中定义十分简单:

// A bucket for a Go map.
type bmap struct {
    // tophash generally contains the top byte of the hash value
    // for each key in this bucket. If tophash[0] < minTopHash,
    // tophash[0] is a bucket evacuation state instead.
    tophash [bucketCnt]uint8
    // Followed by bucketCnt keys and then bucketCnt elems.
    // NOTE: packing all the keys together and then all the elems together makes the
    // code a bit more complicated than alternating key/elem/key/elem/... but it allows
    // us to eliminate padding which would be needed for, e.g., map[int64]int8.
    // Followed by an overflow pointer.
}

但其实真正的在内存中分配的结构体是这样的:

// A bucket for a Go map.
type bmap struct {
    // tophash generally contains the top byte of the hash value
    // for each key in this bucket. If tophash[0] < minTopHash,
    // tophash[0] is a bucket evacuation state instead.
    tophash [bucketCnt]uint8
    keys [bucketCnt]string // 由于我举例的key是string,故我这里写string
    values [bucketCnt]string // 由于上面我的例子的value的类型是string,故这里也是string
    pointer unsafe.pointer  // 由于key和value都是指针,所以这里是一个指针
    // Followed by bucketCnt keys and then bucketCnt elems.
    // NOTE: packing all the keys together and then all the elems together makes the
    // code a bit more complicated than alternating key/elem/key/elem/... but it allows
    // us to eliminate padding which would be needed for, e.g., map[int64]int8.
    // Followed by an overflow pointer.
}

隐藏的字段在map源码中都是靠地址偏移来得到,tophash我们能轻易找到位置,但是如何找到keys、values和pointer呢? 在map中是这么做的:

dataOffset = unsafe.Offsetof(struct {
        b bmap
        v int64
    }{}.v)

在64位机器上,需要对齐8个字节,这里int64正好也是8个字节,所以恰好解决内存对齐的问题,找到v的起始地址也就是values的起始地址:

dataOffset+bucketCnt*2*sys.PtrSize // string16个字节,相当于2个指针,bucketCnt等于8

pointer的起始地址

dataOffset+bucketCnt*2*sys.PtrSize+sys.PtrSize

tophash存的是key的hash高8位,为了方便查找key,为什么keys和values分别存在一堆呢?不是k|v|k|v这种呢?由于key和value的变量类型可能不一样,对齐系数不一致,可能导致内存不紧凑而浪费内存,所以把8个keys存到一堆,8个values存到一堆,然后最后在pointer之前对齐就可以了。所以此时也能算出来整个bmap的大小:

bucketCnt*(uint8的字节为1)+bucketCnt*(string的字节16)+bucketCnt*(string的字节16)+指针大小8字节 = 272

在真正调试的时候如查看bucket里面的具体的key和value呢?这里给大家展示一个小技巧,如果大家有其他方法,可以留言讨论:

type dmap struct {
    tophash        [bucketCnt]uint8
    debugKeys      [bucketCnt]string
    debugElems     [bucketCnt]string
    //debugOverflows unsafe.Pointer
    debugOverflows uintptr
}

这是我定义的调试结构体,将该代码和bmap的结构体放到一堆,当你获取到bmap桶的地址的时候,就可以如下转换,就可以查看bmap的具体值了:

b0 := (*dmap)(add(buckets, uintptr(0)*uintptr(t.bucketsize)))
        println(b0.debugOverflows)

buckets假设是桶数组的起始地址,加上bucketsize就会得到第二个桶的起始地址,然后直接转型为*dmap,最后你可以可以打印出来你想查看的真实的值了。

map的整体结构

c04fe0552f6e526973673711b868fa68.png

如果申请内存桶的时候又多余的溢出桶,那么mapextra的nextOverflow就会指向[]bmap其中的某块桶的地址,地址后之后的桶都是溢出桶。在一个桶装不下的时候,会去溢出桶拿桶然后bmap的overflow指向溢出桶。

总结

上面大概介绍了map的数据结构,后面系列map的具体代码分析,包括增、删、改、查、扩容等都会分篇细解,如有不足之处,请共同讨论学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值