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

本文探讨了Go语言中map的重要性和实现方式,通过分析源码,详细讲解了hmap、bucket(bmap)结构及其工作原理。文章介绍了如何找到map对应的源码,并解析了map的内存对齐和溢出桶管理,为后续的map操作分析奠定了基础。
摘要由CSDN通过智能技术生成

为什么分析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	""..
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangshen023

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值