go基础之map-写在前面(一)
为什么分析map
在计算机编程语言当中,用的最多的数据结构估计就是map。map以他近乎o(1)的查找效率和修改效率让他在大多数场景下都比较受青睐。map的常规的实现方式都是hash+其他数据结构,如java是hash+红黑树,而我现在即将要分析的go的实现方式是hash+链表。我会分析map的几乎每段代码,并且在我的GitHub可以查看到我的分析,注释十分详尽,欢迎批评指正。我的打算是把一些常用的数据结构都分析一遍,如果有志同道合的人,可以联系我。
我的环境
为了给那些感兴趣看源码分析我的博客的同学阅读得更加清晰,列举了我的环境:
- go1.14.7 amd64;
- windows和mac接口,linux没有测试,估计没问题 ;
- goland,目前最好的golang ide,虽然笔者用起来感觉还是不太完美;
- 着重分析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 ""..