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 mainimport "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=0x2880x0000 00000 (main.go:5)    TEXT    "".main(SB), ABIInternal, $648-00x0000 00000 (main.go:5)    MOVQ    TLS, CX0x0009 00009 (main.go:5)    PCDATA  $0, $-20x0009 00009 (main.go:5)    MOVQ    (CX)(TLS*2), CX0x0010 00016 (main.go:5)    PCDATA  $0, $-10x0010 00016 (main.go:5)    LEAQ    -520(SP), AX0x0018 00024 (main.go:5)    CMPQ    AX, 16(CX)0x001c 00028 (main.go:5)    PCDATA  $0, $-20x001c 00028 (main.go:5)    JLS 18810x0022 00034 (main.go:5)    PCDATA  $0, $-10x0022 00034 (main.go:5)    SUBQ    $648, SP0x0029 00041 (main.go:5)    MOVQ    BP, 640(SP)0x0031 00049 (main.go:5)    LEAQ    640(SP), BP0x0039 00057 (main.go:5)    PCDATA  $0, $-20x0039 00057 (main.go:5)    PCDATA  $1, $-20x0039 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, $00x0039 00057 (main.go:6)    PCDATA  $1, $00x0039 00057 (main.go:6)    CALL    runtime.makemap_small(SB)0x003e 00062 (main.go:6)    PCDATA  $0, $10x003e 00062 (main.go:6)    MOVQ    (SP), AX0x0042 00066 (main.go:6)    MOVQ    AX, "".m1+80(SP)0x0047 00071 (main.go:7)    PCDATA  $0, $00x0047 00071 (main.go:7)    PCDATA  $1, $10x0047 00071 (main.go:7)    MOVQ    AX, ""..autotmp_10+200(SP)0x004f 00079 (main.go:7)    PCDATA  $1, $20x004f 00079 (main.go:7)    XORPS   X0, X00x0052 00082 (main.go:7)    MOVUPS  X0, ""..autotmp_9+272(SP)0x005a 00090 (main.go:7)    PCDATA  $0, $10x005a 00090 (main.go:7)    PCDATA  $1, $10x005a 00090 (main.go:7)    LEAQ    ""..autotmp_9+272(SP), AX0x0062 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, $20x006c 00108 (main.go:7)    PCDATA  $1, $00x006c 00108 (main.go:7)    MOVQ    ""..autotmp_10+200(SP), CX0x0074 00116 (main.go:7)    PCDATA  $0, $30x0074 00116 (main.go:7)    LEAQ    type.map[string]string(SB), DX0x007b 00123 (main.go:7)    PCDATA  $0, $20x007b 00123 (main.go:7)    MOVQ    DX, ""..autotmp_9+272(SP)0x0083 00131 (main.go:7)    PCDATA  $0, $10x0083 00131 (main.go:7)    MOVQ    CX, ""..autotmp_9+280(SP)0x008b 00139 (main.go:7)    TESTB   AL, (AX)0x008d 00141 (main.go:7)    JMP 1430x008f 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, $00x00af 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, $10x00cf 00207 (main.go:8)    MOVQ    (SP), AX0x00d3 00211 (main.go:8)    MOVQ    AX, "".m2+72(SP)0x00d8 00216 (main.go:9)    PCDATA  $0, $00x00d8 00216 (main.go:9)    PCDATA  $1, $10x00d8 00216 (main.go:9)    MOVQ    AX, ""..autotmp_10+200(SP)0x00e0 00224 (main.go:9)    PCDATA  $1, $20x00e0 00224 (main.go:9)    XORPS   X0, X00x00e3 00227 (main.go:9)    MOVUPS  X0, ""..autotmp_9+272(SP)0x00eb 00235 (main.go:9)    PCDATA  $0, $10x00eb 00235 (main.go:9)    PCDATA  $1, $10x00eb 00235 (main.go:9)    LEAQ    ""..autotmp_9+272(SP), AX0x00f3 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, $20x00fd 00253 (main.go:9)    PCDATA  $1, $00x00fd 00253 (main.go:9)    MOVQ    ""..autotmp_10+200(SP), CX0x0105 00261 (main.go:9)    PCDATA  $0, $30x0105 00261 (main.go:9)    LEAQ    type.map[string]string(SB), DX0x010c 00268 (main.go:9)    PCDATA  $0, $20x010c 00268 (main.go:9)    MOVQ    DX, ""..autotmp_9+272(SP)0x0114 00276 (main.go:9)    PCDATA  $0, $10x0114 00276 (main.go:9)    MOVQ    CX, ""..autotmp_9+280(SP)0x011c 00284 (main.go:9)    TESTB   AL, (AX)0x011e 00286 (main.go:9)    JMP 2880x0120 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, $00x0140 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, $10x015b 00347 (main.go:10)   LEAQ    type.map[string]string(SB), AX0x0162 00354 (main.go:10)   PCDATA  $0, $00x0162 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, $10x017d 00381 (main.go:10)   MOVQ    24(SP), AX0x0182 00386 (main.go:10)   PCDATA  $1, $30x0182 00386 (main.go:10)   MOVQ    AX, "".m3+64(SP)0x0187 00391 (main.go:11)   PCDATA  $0, $00x0187 00391 (main.go:11)   PCDATA  $1, $40x0187 00391 (main.go:11)   MOVQ    AX, ""..autotmp_10+200(SP)0x018f 00399 (main.go:11)   PCDATA  $1, $50x018f 00399 (main.go:11)   XORPS   X0, X00x0192 00402 (main.go:11)   MOVUPS  X0, ""..autotmp_9+272(SP)0x019a 00410 (main.go:11)   PCDATA  $0, $10x019a 00410 (main.go:11)   PCDATA  $1, $40x019a 00410 (main.go:11)   LEAQ    ""..autotmp_9+272(SP), AX0x01a2 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, $20x01ac 00428 (main.go:11)   PCDATA  $1, $30x01ac 00428 (main.go:11)   MOVQ    ""..autotmp_10+200(SP), CX0x01b4 00436 (main.go:11)   PCDATA  $0, $30x01b4 00436 (main.go:11)   LEAQ    type.map[string]string(SB), DX0x01bb 00443 (main.go:11)   PCDATA  $0, $20x01bb 00443 (main.go:11)   MOVQ    DX, ""..autotmp_9+272(SP)0x01c3 00451 (main.go:11)   PCDATA  $0, $10x01c3 00451 (main.go:11)   MOVQ    CX, ""..autotmp_9+280(SP)0x01cb 00459 (main.go:11)   TESTB   AL, (AX)0x01cd 00461 (main.go:11)   JMP 4630x01cf 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, $00x01ef 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, $10x020f 00527 (main.go:12)   MOVQ    (SP), AX0x0213 00531 (main.go:12)   PCDATA  $0, $00x0213 00531 (main.go:12)   PCDATA  $1, $60x0213 00531 (main.go:12)   MOVQ    AX, "".m4+56(SP)0x0218 00536 (main.go:13)   PCDATA  $0, $10x0218 00536 (main.go:13)   PCDATA  $1, $30x0218 00536 (main.go:13)   MOVQ    "".m4+56(SP), AX0x021d 00541 (main.go:13)   PCDATA  $0, $00x021d 00541 (main.go:13)   PCDATA  $1, $40x021d 00541 (main.go:13)   MOVQ    AX, ""..autotmp_10+200(SP)0x0225 00549 (main.go:13)   PCDATA  $1, $50x0225 00549 (main.go:13)   XORPS   X0, X00x0228 00552 (main.go:13)   MOVUPS  X0, ""..autotmp_9+272(SP)0x0230 00560 (main.go:13)   PCDATA  $0, $10x0230 00560 (main.go:13)   PCDATA  $1, $40x0230 00560 (main.go:13)   LEAQ    ""..autotmp_9+272(SP), AX0x0238 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, $20x0242 00578 (main.go:13)   PCDATA  $1, $30x0242 00578 (main.go:13)   MOVQ    ""..autotmp_10+200(SP), CX0x024a 00586 (main.go:13)   PCDATA  $0, $30x024a 00586 (main.go:13)   LEAQ    type.map[string]string(SB), DX0x0251 00593 (main.go:13)   PCDATA  $0, $20x0251 00593 (main.go:13)   MOVQ    DX, ""..autotmp_9+272(SP)0x0259 00601 (main.go:13)   PCDATA  $0, $10x0259 00601 (main.go:13)   MOVQ    CX, ""..autotmp_9+280(SP)0x0261 00609 (main.go:13)   TESTB   AL, (AX)0x0263 00611 (main.go:13)   JMP 6130x0265 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, $00x0285 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, $10x02a0 00672 (main.go:14)   LEAQ    type.map[string]string(SB), AX0x02a7 00679 (main.go:14)   PCDATA  $0, $00x02a7 00679 (main.go:14)   MOVQ    AX, (SP)0x02ab 00683 (main.go:14)   PCDATA  $0, $10x02ab 00683 (main.go:14)   MOVQ    "".m3+64(SP), AX0x02b0 00688 (main.go:14)   PCDATA  $0, $00x02b0 00688 (main.go:14)   MOVQ    AX, 8(SP)0x02b5 00693 (main.go:14)   PCDATA  $0, $10x02b5 00693 (main.go:14)   LEAQ    go.string."1"(SB), AX0x02bc 00700 (main.go:14)   PCDATA  $0, $00x02bc 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, $40x02cf 00719 (main.go:14)   MOVQ    32(SP), DI0x02d4 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, $-20x02e6 00742 (main.go:14)   PCDATA  $1, $-20x02e6 00742 (main.go:14)   CMPL    runtime.writeBarrier(SB), $00x02ed 00749 (main.go:14)   JEQ 7560x02ef 00751 (main.go:14)   JMP 18640x02f4 00756 (main.go:14)   LEAQ    go.string."2"(SB), AX0x02fb 00763 (main.go:14)   MOVQ    AX, (DI)0x02fe 00766 (main.go:14)   JMP 7680x0300 00768 (main.go:15)   PCDATA  $0, $10x0300 00768 (main.go:15)   PCDATA  $1, $30x0300 00768 (main.go:15)   MOVQ    "".m3+64(SP), AX0x0305 00773 (main.go:15)   PCDATA  $0, $00x0305 00773 (main.go:15)   PCDATA  $1, $40x0305 00773 (main.go:15)   MOVQ    AX, ""..autotmp_10+200(SP)0x030d 00781 (main.go:15)   PCDATA  $0, $40x030d 00781 (main.go:15)   PCDATA  $1, $70x030d 00781 (main.go:15)   LEAQ    ""..autotmp_11+544(SP), DI0x0315 00789 (main.go:15)   XORPS   X0, X00x0318 00792 (main.go:15)   PCDATA  $0, $00x0318 00792 (main.go:15)   LEAQ    -32(DI), DI0x031c 00796 (main.go:15)   DUFFZERO    $2730x032f 00815 (main.go:15)   PCDATA  $0, $10x032f 00815 (main.go:15)   LEAQ    type.map[string]string(SB), AX0x0336 00822 (main.go:15)   PCDATA  $0, $00x0336 00822 (main.go:15)   MOVQ    AX, (SP)0x033a 00826 (main.go:15)   PCDATA  $0, $10x033a 00826 (main.go:15)   PCDATA  $1, $80x033a 00826 (main.go:15)   MOVQ    ""..autotmp_10+200(SP), AX0x0342 00834 (main.go:15)   PCDATA  $0, $00x0342 00834 (main.go:15)   MOVQ    AX, 8(SP)0x0347 00839 (main.go:15)   PCDATA  $0, $10x0347 00839 (main.go:15)   LEAQ    ""..autotmp_11+544(SP), AX0x034f 00847 (main.go:15)   PCDATA  $0, $00x034f 00847 (main.go:15)   MOVQ    AX, 16(SP)0x0354 00852 (main.go:15)   CALL    runtime.mapiterinit(SB)0x0359 00857 (main.go:15)   JMP 8590x035b 00859 (main.go:15)   CMPQ    ""..autotmp_11+544(SP), $00x0364 00868 (main.go:15)   JNE 8750x0366 00870 (main.go:15)   JMP 13290x036b 00875 (main.go:15)   PCDATA  $0, $10x036b 00875 (main.go:15)   MOVQ    ""..autotmp_11+552(SP), AX0x0373 00883 (main.go:15)   TESTB   AL, (AX)0x0375 00885 (main.go:15)   MOVQ    8(AX), CX0x0379 00889 (main.go:15)   MOVQ    (AX), AX0x037c 00892 (main.go:15)   PCDATA  $0, $00x037c 00892 (main.go:15)   PCDATA  $1, $90x037c 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, $10x038c 00908 (main.go:15)   MOVQ    ""..autotmp_11+544(SP), AX0x0394 00916 (main.go:15)   TESTB   AL, (AX)0x0396 00918 (main.go:15)   MOVQ    8(AX), CX0x039a 00922 (main.go:15)   MOVQ    (AX), AX0x039d 00925 (main.go:15)   PCDATA  $0, $00x039d 00925 (main.go:15)   PCDATA  $1, $100x039d 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), AX0x03b5 00949 (main.go:15)   PCDATA  $0, $50x03b5 00949 (main.go:15)   PCDATA  $1, $110x03b5 00949 (main.go:15)   MOVQ    ""..autotmp_25+288(SP), CX0x03bd 00957 (main.go:15)   PCDATA  $0, $00x03bd 00957 (main.go:15)   PCDATA  $1, $120x03bd 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), AX0x03d5 00981 (main.go:16)   PCDATA  $0, $50x03d5 00981 (main.go:16)   PCDATA  $1, $130x03d5 00981 (main.go:16)   MOVQ    "".k+256(SP), CX0x03dd 00989 (main.go:16)   PCDATA  $0, $00x03dd 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, $10x03eb 01003 (main.go:16)   MOVQ    16(SP), AX0x03f0 01008 (main.go:16)   PCDATA  $0, $00x03f0 01008 (main.go:16)   PCDATA  $1, $140x03f0 01008 (main.go:16)   MOVQ    AX, ""..autotmp_26+152(SP)0x03f8 01016 (main.go:16)   PCDATA  $1, $150x03f8 01016 (main.go:16)   XORPS   X0, X00x03fb 01019 (main.go:16)   MOVUPS  X0, ""..autotmp_9+272(SP)0x0403 01027 (main.go:16)   PCDATA  $0, $10x0403 01027 (main.go:16)   PCDATA  $1, $140x0403 01027 (main.go:16)   LEAQ    ""..autotmp_9+272(SP), AX0x040b 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, $20x0415 01045 (main.go:16)   PCDATA  $1, $130x0415 01045 (main.go:16)   MOVQ    ""..autotmp_26+152(SP), CX0x041d 01053 (main.go:16)   PCDATA  $0, $30x041d 01053 (main.go:16)   LEAQ    type.string(SB), DX0x0424 01060 (main.go:16)   PCDATA  $0, $20x0424 01060 (main.go:16)   MOVQ    DX, ""..autotmp_9+272(SP)0x042c 01068 (main.go:16)   PCDATA  $0, $10x042c 01068 (main.go:16)   MOVQ    CX, ""..autotmp_9+280(SP)0x0434 01076 (main.go:16)   TESTB   AL, (AX)0x0436 01078 (main.go:16)   JMP 10800x0438 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, $00x0458 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), AX0x047b 01147 (main.go:17)   PCDATA  $0, $50x047b 01147 (main.go:17)   PCDATA  $1, $80x047b 01147 (main.go:17)   MOVQ    "".v+240(SP), CX0x0483 01155 (main.go:17)   PCDATA  $0, $00x0483 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, $10x0491 01169 (main.go:17)   MOVQ    16(SP), AX0x0496 01174 (main.go:17)   PCDATA  $0, $00x0496 01174 (main.go:17)   PCDATA  $1, $160x0496 01174 (main.go:17)   MOVQ    AX, ""..autotmp_29+136(SP)0x049e 01182 (main.go:17)   PCDATA  $1, $170x049e 01182 (main.go:17)   XORPS   X0, X00x04a1 01185 (main.go:17)   MOVUPS  X0, ""..autotmp_9+272(SP)0x04a9 01193 (main.go:17)   PCDATA  $0, $10x04a9 01193 (main.go:17)   PCDATA  $1, $160x04a9 01193 (main.go:17)   LEAQ    ""..autotmp_9+272(SP), AX0x04b1 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, $20x04bb 01211 (main.go:17)   PCDATA  $1, $80x04bb 01211 (main.go:17)   MOVQ    ""..autotmp_29+136(SP), CX0x04c3 01219 (main.go:17)   PCDATA  $0, $30x04c3 01219 (main.go:17)   LEAQ    type.string(SB), DX0x04ca 01226 (main.go:17)   PCDATA  $0, $20x04ca 01226 (main.go:17)   MOVQ    DX, ""..autotmp_9+272(SP)0x04d2 01234 (main.go:17)   PCDATA  $0, $10x04d2 01234 (main.go:17)   MOVQ    CX, ""..autotmp_9+280(SP)0x04da 01242 (main.go:17)   TESTB   AL, (AX)0x04dc 01244 (main.go:17)   JMP 12460x04de 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, $00x04fe 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 13070x051b 01307 (main.go:15)   PCDATA  $0, $10x051b 01307 (main.go:15)   LEAQ    ""..autotmp_11+544(SP), AX0x0523 01315 (main.go:15)   PCDATA  $0, $00x0523 01315 (main.go:15)   MOVQ    AX, (SP)0x0527 01319 (main.go:15)   CALL    runtime.mapiternext(SB)0x052c 01324 (main.go:15)   JMP 8590x0531 01329 (main.go:19)   PCDATA  $0, $10x0531 01329 (main.go:19)   PCDATA  $1, $30x0531 01329 (main.go:19)   LEAQ    type.map[string]string(SB), AX0x0538 01336 (main.go:19)   PCDATA  $0, $00x0538 01336 (main.go:19)   MOVQ    AX, (SP)0x053c 01340 (main.go:19)   PCDATA  $0, $10x053c 01340 (main.go:19)   MOVQ    "".m3+64(SP), AX0x0541 01345 (main.go:19)   PCDATA  $0, $00x0541 01345 (main.go:19)   MOVQ    AX, 8(SP)0x0546 01350 (main.go:19)   PCDATA  $0, $10x0546 01350 (main.go:19)   LEAQ    go.string."1"(SB), AX0x054d 01357 (main.go:19)   PCDATA  $0, $00x054d 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, $10x0560 01376 (main.go:19)   MOVQ    32(SP), AX0x0565 01381 (main.go:19)   PCDATA  $0, $20x0565 01381 (main.go:19)   MOVQ    (AX), CX0x0568 01384 (main.go:19)   PCDATA  $0, $50x0568 01384 (main.go:19)   MOVQ    8(AX), AX0x056c 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, $00x057c 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, $10x058a 01418 (main.go:20)   MOVQ    16(SP), AX0x058f 01423 (main.go:20)   PCDATA  $0, $00x058f 01423 (main.go:20)   PCDATA  $1, $180x058f 01423 (main.go:20)   MOVQ    AX, ""..autotmp_32+120(SP)0x0594 01428 (main.go:20)   PCDATA  $1, $190x0594 01428 (main.go:20)   XORPS   X0, X00x0597 01431 (main.go:20)   MOVUPS  X0, ""..autotmp_9+272(SP)0x059f 01439 (main.go:20)   PCDATA  $0, $10x059f 01439 (main.go:20)   PCDATA  $1, $180x059f 01439 (main.go:20)   LEAQ    ""..autotmp_9+272(SP), AX0x05a7 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, $20x05ae 01454 (main.go:20)   PCDATA  $1, $30x05ae 01454 (main.go:20)   MOVQ    ""..autotmp_32+120(SP), CX0x05b3 01459 (main.go:20)   PCDATA  $0, $30x05b3 01459 (main.go:20)   LEAQ    type.string(SB), DX0x05ba 01466 (main.go:20)   PCDATA  $0, $20x05ba 01466 (main.go:20)   MOVQ    DX, ""..autotmp_9+272(SP)0x05c2 01474 (main.go:20)   PCDATA  $0, $10x05c2 01474 (main.go:20)   MOVQ    CX, ""..autotmp_9+280(SP)0x05ca 01482 (main.go:20)   TESTB   AL, (AX)0x05cc 01484 (main.go:20)   JMP 14860x05ce 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, $00x05ee 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, X00x060c 01548 (main.go:21)   MOVUPS  X0, ""..autotmp_12+336(SP)0x0614 01556 (main.go:21)   PCDATA  $0, $10x0614 01556 (main.go:21)   LEAQ    type.map[string]string(SB), AX0x061b 01563 (main.go:21)   PCDATA  $0, $00x061b 01563 (main.go:21)   MOVQ    AX, (SP)0x061f 01567 (main.go:21)   PCDATA  $0, $10x061f 01567 (main.go:21)   PCDATA  $1, $00x061f 01567 (main.go:21)   MOVQ    "".m3+64(SP), AX0x0624 01572 (main.go:21)   PCDATA  $0, $00x0624 01572 (main.go:21)   MOVQ    AX, 8(SP)0x0629 01577 (main.go:21)   PCDATA  $0, $10x0629 01577 (main.go:21)   LEAQ    go.string."1"(SB), AX0x0630 01584 (main.go:21)   PCDATA  $0, $00x0630 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, $10x0643 01603 (main.go:21)   MOVQ    32(SP), AX0x0648 01608 (main.go:21)   PCDATA  $0, $00x0648 01608 (main.go:21)   PCDATA  $1, $200x0648 01608 (main.go:21)   MOVQ    AX, ""..autotmp_35+104(SP)0x064d 01613 (main.go:21)   MOVBLZX 40(SP), AX0x0652 01618 (main.go:21)   MOVB    AL, ""..autotmp_13+55(SP)0x0656 01622 (main.go:21)   PCDATA  $0, $10x0656 01622 (main.go:21)   PCDATA  $1, $00x0656 01622 (main.go:21)   MOVQ    ""..autotmp_35+104(SP), AX0x065b 01627 (main.go:21)   MOVQ    8(AX), CX0x065f 01631 (main.go:21)   MOVQ    (AX), AX0x0662 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, $00x0672 01650 (main.go:21)   PCDATA  $1, $210x0672 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), AX0x0687 01671 (main.go:21)   MOVB    AL, "".ok+54(SP)0x068b 01675 (main.go:21)   CMPB    "".ok+54(SP), $00x0690 01680 (main.go:21)   JNE 16870x0692 01682 (main.go:21)   JMP 18620x0697 01687 (main.go:22)   MOVQ    "".v2+216(SP), AX0x069f 01695 (main.go:22)   PCDATA  $0, $50x069f 01695 (main.go:22)   PCDATA  $1, $00x069f 01695 (main.go:22)   MOVQ    "".v2+208(SP), CX0x06a7 01703 (main.go:22)   PCDATA  $0, $00x06a7 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, $10x06b5 01717 (main.go:22)   MOVQ    16(SP), AX0x06ba 01722 (main.go:22)   PCDATA  $0, $00x06ba 01722 (main.go:22)   PCDATA  $1, $220x06ba 01722 (main.go:22)   MOVQ    AX, ""..autotmp_36+96(SP)0x06bf 01727 (main.go:22)   PCDATA  $1, $230x06bf 01727 (main.go:22)   XORPS   X0, X00x06c2 01730 (main.go:22)   MOVUPS  X0, ""..autotmp_9+272(SP)0x06ca 01738 (main.go:22)   PCDATA  $0, $10x06ca 01738 (main.go:22)   PCDATA  $1, $220x06ca 01738 (main.go:22)   LEAQ    ""..autotmp_9+272(SP), AX0x06d2 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, $20x06d9 01753 (main.go:22)   PCDATA  $1, $00x06d9 01753 (main.go:22)   MOVQ    ""..autotmp_36+96(SP), CX0x06de 01758 (main.go:22)   PCDATA  $0, $30x06de 01758 (main.go:22)   LEAQ    type.string(SB), DX0x06e5 01765 (main.go:22)   PCDATA  $0, $20x06e5 01765 (main.go:22)   MOVQ    DX, ""..autotmp_9+272(SP)0x06ed 01773 (main.go:22)   PCDATA  $0, $10x06ed 01773 (main.go:22)   MOVQ    CX, ""..autotmp_9+280(SP)0x06f5 01781 (main.go:22)   TESTB   AL, (AX)0x06f7 01783 (main.go:22)   JMP 17850x06f9 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, $00x0719 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 18460x0736 01846 (<unknown line number>)    PCDATA  $0, $-10x0736 01846 (<unknown line number>)    PCDATA  $1, $-10x0736 01846 (<unknown line number>)    MOVQ    640(SP), BP0x073e 01854 (<unknown line number>)    ADDQ    $648, SP0x0745 01861 (<unknown line number>)    RET0x0746 01862 (main.go:21)   JMP 18460x0748 01864 (main.go:14)   PCDATA  $0, $-20x0748 01864 (main.go:14)   PCDATA  $1, $-20x0748 01864 (main.go:14)   LEAQ    go.string."2"(SB), AX0x074f 01871 (main.go:14)   CALL    runtime.gcWriteBarrier(SB)0x0754 01876 (main.go:14)   JMP 7680x0759 01881 (main.go:14)   NOP0x0759 01881 (main.go:5)    PCDATA  $1, $-10x0759 01881 (main.go:5)    PCDATA  $0, $-20x0759 01881 (main.go:5)    CALL    runtime.morestack_noctxt(SB)0x075e 01886 (main.go:5)    PCDATA  $0, $-10x075e 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    *[]*bmapoldoverflow *[]*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]uint8keys [bucketCnt]string // 由于我舉例的key是string,故我這里寫stringvalues [bucketCnt]string // 由于上面我的例子的value的類型是string,故這里也是stringpointer 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 bmapv 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]uint8debugKeys      [bucketCnt]stringdebugElems     [bucketCnt]string//debugOverflows unsafe.PointerdebugOverflows 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的具體代碼分析,包括增、刪、改、查、擴容等都會分篇細解,如有不足之處,請共同討論學習。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/529619.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/529619.shtml
英文地址,請注明出處:http://en.pswp.cn/news/529619.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

大學數學建模大賽是用計算機,北京大學第十屆“江澤涵杯”數學建模與計算機應用競賽試題...

消息來源&#xff1a;http://www.math.pku.edu.cn:8000/news/read.php?newsid8014A題&#xff1a;投籃問題投籃是籃球運動中一項關鍵性技術&#xff0c;是一項重要的得分手段。在籃球賽中有三種特殊的投籃方式&#xff0c;“三分球”、“兩分球”和“一分球(罰籃)”。其中&…

dynamo方程怎么寫_【簡明自控】為什么特征方程如此重要

簡明自動控制——為什么特征方程如此重要。熱場視頻&#xff1a;自平衡桿-雙軸反作用輪倒立擺_嗶哩嗶哩 (゜-゜)つロ 干杯~-bilibili?www.bilibili.com頂個棍子&#xff01;具有主動腳輪的全向移動機器人_嗶哩嗶哩 (゜-゜)つロ 干杯~-bilibili?www.bilibili.com我自行車怎么少…

用戶計算機可以通過電話撥號,用戶計算機可以通過大型局域網、小型局域網、無線連接、電話撥號和()等方式接入Internet。...

_在保險合同中&#xff0c;用于體現保險利益載體的保險對象條款&#xff0c;被稱為()條款。何為C/H比&#xff1f;原料中的C/H比與原性能的關系是什么&#xff1f;選址意見書、規劃條件、建設用地規劃許可證、建設工程規劃許可證的有效期為()福建木偶戲頗負盛名&#xff0c;以(…

和佳股份有沒有納米機器人_新高賽復賽入圍項目(49)一種納米硅質絕熱材料及其制備方法...

點擊上方“藍字”關注我們“2020中國山東新舊動能轉換高價值專利培育大賽”(簡稱“新高賽”)是由山東省市場監督管理局(知識產權局)主辦&#xff0c;由山東省知識產權事業發展中心、知識產權出版社有限責任公司共同承辦的以新舊動能轉換高價值專利培育為主題的創新大賽。新高賽…

分數乘整數計算機在線應用,分數乘整數應用題.doc

分數乘法應用題【知識要點】求一個數的幾分之幾是多少和求一個數的幾倍是多少的分數應用題的解題思路和解答方法。1、一本書100頁&#xff0c;看了&#xff0c;看了多少頁&#xff1f;想&#xff1a;看了&#xff0c;是看了 的&#xff0c;就是把 看作單位“1”&#xff0c;求看…

mastercam加工報表生成_2020北京加工中心編程培訓工廠教學行業

2020北京加工中心編程培訓工廠教學行業河北德瑪數控培訓自辦工廠 全程四軸五軸實踐 學生直接面對客戶 承攬加工各種異形件復雜件 終身技術支持 可勤工儉學 解決企業各種技術問題&#xff0c;每個校區都有實訓車間&#xff0c;實訓圖檔不限、不限、時間不限、并且不另收費&#…

背景調查 跳槽_分享 | 錄用背景調查,查的到底是什么?

招聘對于HR而言&#xff0c;是一項常規工作&#xff0c;同時也是一項非常重要的工作&#xff0c;招聘有一系列的步驟和程序&#xff0c;每一道步驟和程序都必不可少&#xff0c;顯得那么的重要&#xff0c;這其中包括我們常說的筆試、面試、體檢&#xff0c;還包括不常說的正式…

html鏈接word,word添加網址超鏈接方法

word添加網址超鏈接方法大家對于超鏈接都了解嗎&#xff1f;那么在word中應該如何設置超鏈接呢&#xff1f;下面是小編分享給大家的word添加網址超鏈接方法&#xff0c;希望對大家有幫助。1、直接拖動選定文本這個方法是最簡單的方法&#xff0c;在word文檔中直接拖動鼠選定的文…

.class文件轉換.java_Java中的動態鏈接VS操作系統動態鏈接

在操作系統OS中為了優化內存的使用會采用一種動態鏈接方式&#xff0c;一個文件想要在操作系統中運行必須經過編譯、匯編譯、鏈接、裝載等步驟。可以參考Java程序是怎么跑起來的。本篇主要講解Java棧幀中動態鏈接部分與操作系統的的動態鏈接的區別與聯系操縱系統為什么需要動態…

計算機組成原理與應用,計算機組成原理簡答與應用

簡答與應用1&#xff0e;何謂中斷&#xff1f;&#xff1f;中斷是由外圍設備或其他非預期的急需處理的事件引起的&#xff0c;CPU暫時中斷正在執行的程序&#xff0c;轉至另一服務程序去處理這一事件&#xff0c;待事件處理完畢后返回原程序繼續執行。2.(不算CPU中的寄存器級)存…

宏觀經濟學gdp計算方法_宏觀經濟學考研的重要考點

宏觀經濟學考研重要考點西方國民收入核算宏觀經濟學的特點;國內生產總值;核算國民收入的兩種算法(支出法和收入法);國內生產總值;個人可支配收入;國民收入的基本公式;名義GDP和實際GDP。要求&#xff1a;重點掌握本章基本概念及計算。簡單國民收入決定理論均衡產出;凱恩斯的消費…

大學計算機基礎試題 選擇題,大學計算機基礎試題選擇題

大學計算機基礎試題選擇題第一章1. 世界上第一臺全自動電子數字計算機ENIAC的誕生時間是( )A. 1945年 B. 1946年 C. 1948年 D. 1949年2. 第一位提出“存儲程序”思想的科學家是( )A. 圖靈 B. 萊布尼茨 C. 馮諾伊曼 D. 帕斯卡3. 電子計算機四個發展階段的劃分依據是( )不同A. 電…

json符號解釋大全_牛年汪姓男孩高端大氣的名字大全

牛年汪姓男孩高端大氣的名字大全 張桉寧起名分享牛年汪姓男孩高端大氣的名字大全&#xff1a;給男孩起名有很多的講究&#xff0c;需要從多個方面考慮。牛年汪姓男孩如何起一個高端大氣的好名字&#xff0c;是家長朋友們都十分重視的。給牛年的汪姓男孩起一個高端的名字&#x…

變電站計算機在線監控系統,變電站環境在線監測系統

原標題&#xff1a;變電站環境在線監測系統概述隨著計算機技術、網絡通訊技術以及電力系統保護技術的發展&#xff0c;配電室的自動化運行水平不斷提高&#xff0c;大大減少了人為操作&#xff0c;使配電室的無人值守逐步變成了可能。配電的可靠和安全是整個電能管理系統中的一…

什么意思是誰_舔狗是什么意思?如果不是真的喜歡誰又愿意做舔狗呢出處?

[海峽網]網絡上面經常會出現一些新的詞句&#xff0c;比如最近舔狗這個詞就經常出現在大家的視線中。相信很多小伙伴都知道&#xff0c;最近關于虎牙的包子的事情也是挺多的&#xff0c;不過關于包桑的梗也是很多&#xff0c;那么關于包桑的這句“如果不是真的喜歡&#xff0c;…

計算機控制面板圖標顯示,Win8桌面如何有計算機/控制面板圖標

Win8桌面如何有計算機/控制面板圖標2013年06月04日 00:44作者&#xff1a;馬承平編輯&#xff1a;馬承平文章出處&#xff1a;泡泡網原創分享泡泡網系統工具頻道6月4日 全新Windows8系統給我們帶來不僅是超炫的動態磁貼展示&#xff0c;更有新增超級按鈕項&#xff0c;它大大集…

【Android 13】使用Android Studio調試系統應用之Settings移植(二):構建settings app項目目錄

文章目錄 一、篇頭二、系列文章2.1 Android 13 系列文章2.2 Android 9 系列文章2.3 Android 11 系列文章三、準備工作3.1 創建目錄3.2 初始化 git 倉庫四、提取settings原始代碼4.1 提取目標4.2 源碼路徑4.2.1 settings app4.2.2 SettingsLib4.3 存放位置

dog log 算子_DoG和LoG算子

DoG(Difference of Gaussian)算子和LoG(Laplacian of Gaussian)算子是常用的極值點檢測(Blob Detection)兩種方法&#xff0c;高斯卷積是為了進行尺度變換&#xff0c;那么LapLacian呢。 因此這里首先引入LapLacian算子。圖像邊緣檢測因此進行邊緣檢測有兩種方法。一階導數的極…

計算機專業好還是鐵道運輸管理好,鐵道運輸管理專業主要是干什么的?

鐵道運輸管理專業主要是干什么的?鐵道運輸管理專業主要學什么&#xff1f;學鐵道運營管理好就業嗎&#xff1f;1、鐵道交通運營管理專業主要培養德、智、體、美各方面全面發展&#xff0c;掌握所必需的基本理論和專業知識&#xff0c;有較高的綜合素質和較強的鐵道交通運營管理…

大學期末考java編程題_大學java期末考試考試題和答案

題號一二三總分得分得分評卷人一、簡單編程題<共50分)在考試文件夾中新建一個應用程序proj1<應用程序的文件夾名稱為proj1)&#xff0c;按照以下要求編寫程序代碼。b5E2RGbCAP1.在程序中定義Person類&#xff0c;為該類編寫如下字段、構造器、訪問器、修改器和相應的其他…