溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Go語(yǔ)言的make和new實(shí)現(xiàn)原理是什么

發(fā)布時(shí)間:2023-02-27 09:13:40 來(lái)源:億速云 閱讀:91 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹“Go語(yǔ)言的make和new實(shí)現(xiàn)原理是什么”的相關(guān)知識(shí),小編通過(guò)實(shí)際案例向大家展示操作過(guò)程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“Go語(yǔ)言的make和new實(shí)現(xiàn)原理是什么”文章能幫助大家解決問(wèn)題。

概述

雖然 make 和 new  都是能夠用于初始化數(shù)據(jù)結(jié)構(gòu),但是它們兩者能夠初始化的結(jié)構(gòu)類型卻有著較大的不同;make 在 Go 語(yǔ)言中只能用于初始化語(yǔ)言中的基本類型:

slice := make([]int, 0, 100)
hash := make(map[int]bool, 10)
ch := make(chan int, 5)

這些基本類型都是語(yǔ)言為我們提供的,我們?cè)谇懊娴恼鹿?jié)中其實(shí)已經(jīng)介紹過(guò)了它們初始化的過(guò)程以及原理,但是在這里還是需要提醒各位讀者注意的是,這三者返回了不同類型的數(shù)據(jù)結(jié)構(gòu):

  • slice 是一個(gè)包含 data、cap 和 len 的結(jié)構(gòu)體

  • hash 是一個(gè)指向 hmap 結(jié)構(gòu)體的指針;

  • ch 是一個(gè)指向 hchan 結(jié)構(gòu)體的指針

而另一個(gè)用于初始化數(shù)據(jù)結(jié)構(gòu)的關(guān)鍵字 new 的作用其實(shí)就非常簡(jiǎn)單了,它只是接收一個(gè)類型作為參數(shù)然后返回一個(gè)指向這個(gè)類型的指針:

i := new(int)

var v int
i := &v

上述代碼片段中的兩種不同初始化方法其實(shí)是等價(jià)的,它們都會(huì)創(chuàng)建一個(gè)指向 int 零值的指針。

Go語(yǔ)言的make和new實(shí)現(xiàn)原理是什么

到了這里我們對(duì) Go 語(yǔ)言中這兩種不同關(guān)鍵字的使用也有了一定的了解:make 用于創(chuàng)建切片、哈希表和管道等內(nèi)置數(shù)據(jù)結(jié)構(gòu),new 用于分配并創(chuàng)建一個(gè)指向?qū)?yīng)類型的指針。

實(shí)現(xiàn)原理

接下來(lái)我們將分別介紹 make 和 new 在初始化不同數(shù)據(jù)結(jié)構(gòu)時(shí)的具體過(guò)程,我們會(huì)從編譯期間和運(yùn)行時(shí)兩個(gè)不同的階段理解這兩個(gè)關(guān)鍵字的原理,不過(guò)由于前面已經(jīng)詳細(xì)地介紹過(guò) make 的實(shí)現(xiàn)原理,所以我們會(huì)將重點(diǎn)放在 new 上從 Go 語(yǔ)言的源代碼層面分析它的實(shí)現(xiàn)。

make

在前面的章節(jié)中我們其實(shí)已經(jīng)談到過(guò) make 在創(chuàng)建 數(shù)組和切片、哈希表 和 Channel 的具體過(guò)程,所以在這一小節(jié)中,我們也只是會(huì)簡(jiǎn)單提及 make 相關(guān)的數(shù)據(jù)結(jié)構(gòu)初始化原理。

Go語(yǔ)言的make和new實(shí)現(xiàn)原理是什么

在編譯期間的 類型檢查 階段,Go 語(yǔ)言其實(shí)就將代表 make 關(guān)鍵字的 OMAKE 節(jié)點(diǎn)根據(jù)參數(shù)類型的不同轉(zhuǎn)換成了 OMAKESLICE、OMAKEMAP 和 OMAKECHAN 三種不同類型的節(jié)點(diǎn),這些節(jié)點(diǎn)最終也會(huì)調(diào)用不同的運(yùn)行時(shí)函數(shù)來(lái)初始化數(shù)據(jù)結(jié)構(gòu)。

new

內(nèi)置函數(shù) new 會(huì)在編譯期間的 SSA 代碼生成 階段經(jīng)過(guò) callnew 函數(shù)的處理,如果請(qǐng)求創(chuàng)建的類型大小時(shí) 0,那么就會(huì)返回一個(gè)表示空指針的 zerobase 變量,在遇到其他情況時(shí)會(huì)將關(guān)鍵字轉(zhuǎn)換成 newobject

func callnew(t *types.Type) *Node {
    if t.NotInHeap() {
        yyerror("%v is go:notinheap; heap allocation disallowed", t)
    }
    dowidth(t)

    if t.Size() == 0 {
        z := newname(Runtimepkg.Lookup("zerobase"))
        z.SetClass(PEXTERN)
        z.Type = t
        return typecheck(nod(OADDR, z, nil), ctxExpr)
    }

    fn := syslook("newobject")
    fn = substArgTypes(fn, t)
    v := mkcall1(fn, types.NewPtr(t), nil, typename(t))
    v.SetNonNil(true)
    return v
}

需要提到的是,哪怕當(dāng)前變量是使用 var 進(jìn)行初始化,在這一階段可能會(huì)被轉(zhuǎn)換成 newobject 的函數(shù)調(diào)用并在堆上申請(qǐng)內(nèi)存:

func walkstmt(n *Node) *Node {
    switch n.Op {
    case ODCL:
        v := n.Left
        if v.Class() == PAUTOHEAP {
            if prealloc[v] == nil {
                prealloc[v] = callnew(v.Type)
            }
            nn := nod(OAS, v.Name.Param.Heapaddr, prealloc[v])
            nn.SetColas(true)
            nn = typecheck(nn, ctxStmt)
            return walkstmt(nn)
        }
    case ONEW:
        if n.Esc == EscNone {
            r := temp(n.Type.Elem())
            r = nod(OAS, r, nil)
            r = typecheck(r, ctxStmt)
            init.Append(r)
            r = nod(OADDR, r.Left, nil)
            r = typecheck(r, ctxExpr)
            n = r
        } else {
            n = callnew(n.Type.Elem())
        }
    }
}

當(dāng)然這也不是絕對(duì)的,如果當(dāng)前聲明的變量或者參數(shù)不需要在當(dāng)前作用域外『生存』,那么其實(shí)就不會(huì)被初始化在堆上,而是會(huì)初始化在當(dāng)前函數(shù)的棧中并隨著 函數(shù)調(diào)用 的結(jié)束而被銷毀。

newobject 函數(shù)的工作就是獲取傳入類型的大小并調(diào)用 mallocgc 在堆上申請(qǐng)一片大小合適的內(nèi)存空間并返回指向這片內(nèi)存空間的指針:

func newobject(typ *_type) unsafe.Pointer {
    return mallocgc(typ.size, typ, true)
}

mallocgc 函數(shù)的實(shí)現(xiàn)大概有 200 多行代碼,在這一節(jié)中就不展開(kāi)詳細(xì)分析了,我們會(huì)在后面的章節(jié)中詳細(xì)介紹 Go 語(yǔ)言的內(nèi)存管理機(jī)制。

關(guān)于“Go語(yǔ)言的make和new實(shí)現(xiàn)原理是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI