欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang中的new()和make()函數(shù)本質(zhì)區(qū)別

 更新時(shí)間:2025年02月19日 09:44:45   作者:水草  
在 Go 語言開發(fā)中,new() 和 make() 是兩個(gè)容易讓開發(fā)者感到困惑的內(nèi)建函數(shù),盡管它們都用于內(nèi)存分配,但其設(shè)計(jì)目的、適用場景和底層實(shí)現(xiàn)存在本質(zhì)差異,本文將通過類型系統(tǒng)、內(nèi)存模型和編譯器實(shí)現(xiàn)三個(gè)維度,深入解析這兩個(gè)函數(shù)的本質(zhì)區(qū)別,感興趣的朋友一起看看吧

在 Go 語言開發(fā)中,new() 和 make() 是兩個(gè)容易讓開發(fā)者感到困惑的內(nèi)建函數(shù)。盡管它們都用于內(nèi)存分配,但其設(shè)計(jì)目的、適用場景和底層實(shí)現(xiàn)存在本質(zhì)差異。本文將通過類型系統(tǒng)、內(nèi)存模型和編譯器實(shí)現(xiàn)三個(gè)維度,深入解析這兩個(gè)函數(shù)的本質(zhì)區(qū)別。

一、類型系統(tǒng)的哲學(xué)分野

1.1 new() 的通用性設(shè)計(jì)

new(T) 是為所有類型設(shè)計(jì)的通用內(nèi)存分配器,其行為模式高度統(tǒng)一:

// 為 int 類型分配零值內(nèi)存
pInt := new(int)  // *int 類型
// 為自定義結(jié)構(gòu)體分配內(nèi)存
type MyStruct struct { a int }
pStruct := new(MyStruct) // *MyStruct 類型

其核心特征:

  • 返回類型始終為 *T
  • 分配的內(nèi)存被初始化為類型零值
  • 適用于任何類型(包括基本類型、結(jié)構(gòu)體、數(shù)組等)

1.2 make() 的特化使命

make() 是 Go 為特定引用類型設(shè)計(jì)的構(gòu)造器:

// 創(chuàng)建 slice
s := make([]int, 5, 10) 
// 初始化 map
m := make(map[string]int)
// 建立 channel
ch := make(chan int, 5)

關(guān)鍵限制:

  • 僅適用于 slice、map 和 channel 三種類型
  • 返回已初始化的類型實(shí)例(非指針)
  • 支持類型特定的初始化參數(shù)

二、內(nèi)存模型的實(shí)現(xiàn)差異

2.1 new() 的底層機(jī)制

當(dāng)編譯器遇到 new(T) 時(shí):
1.計(jì)算類型大?。簊ize = unsafe.Sizeof(T{})
2.調(diào)用 runtime.newobject 分配內(nèi)存
3.執(zhí)行內(nèi)存清零操作(對應(yīng)零值初始化)
4.返回指向該內(nèi)存的指針

以下偽代碼示意其過程:

func new(T) *T {
    ptr := malloc(sizeof(T))
    *ptr = T{}  // 零值初始化
    return ptr
}

2.2 編譯器前端的語法解析

// 原始代碼片段
type MyStruct struct { a int }
p := new(MyStruct)
// 轉(zhuǎn)換為中間表示 (IR)
ptr := runtime.newobject(unsafe.Pointer(&MyStruct{}))

編譯器會(huì)將 new(T) 替換為對 runtime.newobject 的直接調(diào)用,傳遞類型元信息作為參數(shù)。

2.3 進(jìn)入運(yùn)行時(shí)系統(tǒng)的內(nèi)存分配

runtime.newobject 是 new() 的核心入口,定義于 runtime/malloc.go:

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

關(guān)鍵參數(shù)解釋

  • typ.size: 目標(biāo)類型的大?。ㄓ删幾g器靜態(tài)計(jì)算)
  • typ: 指向類型元數(shù)據(jù)的指針(描述內(nèi)存布局)
  • true: 指示是否需要進(jìn)行清零操作(對應(yīng)零值初始化)

2.4 深入 mallocgc 的內(nèi)存分配流程

mallocgc 是通用內(nèi)存分配函數(shù),負(fù)責(zé)根據(jù)對象大小選擇不同的分配策略:

微小對象分配(Tiny Allocator)
對于小于 16 字節(jié)的對象:

if size <= maxSmallSize {
    if noscan && size < maxTinySize {
        // 使用 per-P 的 tiny allocator
        off := c.tinyoffset
        if off+size <= maxTinySize && c.tiny != 0 {
            x = unsafe.Pointer(c.tiny + off)
            c.tinyoffset = off + size
            return x
        }
        // ...
    }
}
  • 利用線程本地緩存 (mcache) 提升小對象分配速度
  • 合并多個(gè)微對象到一個(gè)內(nèi)存塊,減少碎片

常規(guī)對象分配
對于較大的對象,走標(biāo)準(zhǔn)分配路徑:

var span *mspan
systemstack(func() {
    span = largeAlloc(size, needzero, noscan)
})
x = unsafe.Pointer(span.base())
  • 通過 mheap 全局堆管理器申請新的內(nèi)存頁
  • 涉及復(fù)雜的空閑鏈表查找和頁面分割算法

2.5 make() 的類型特化處理

編譯器將 make 轉(zhuǎn)換為不同的運(yùn)行時(shí)函數(shù)調(diào)用:

類型內(nèi)部函數(shù)關(guān)鍵參數(shù)
sliceruntime.makeslice元素類型、長度、容量
mapruntime.makemap初始 bucket 數(shù)量
channelruntime.makechan緩沖區(qū)大小

以 slice 為例的底層處理流程:

// 編譯器將 make([]int, 5, 10) 轉(zhuǎn)換為
ptr, len, cap := runtime.makeslice(unsafe.Sizeof(int(0)), 5, 10)
return Slice{ptr: ptr, len: 5, cap: 10}

三、零值 vs 就緒狀態(tài)

3.1 new()零值初始化的實(shí)現(xiàn)細(xì)節(jié)

new() 返回的指針指向的內(nèi)存會(huì)被自動(dòng)置零:

if needzero {
    memclrNoHeapPointers(x, size)
}
  • memclrNoHeapPointers 是用匯編編寫的快速清零例程
  • 對不同大小的內(nèi)存塊使用 SIMD 指令優(yōu)化清零速度

3.2 new() 的零值困境

雖然 new() 能完成基本的內(nèi)存分配,但對于復(fù)雜類型可能產(chǎn)生非預(yù)期結(jié)果:

// 創(chuàng)建 slice 指針
sp := new([]int)
*sp = append(*sp, 1)  // 合法但非常規(guī)用法
(*sp)[0] = 1          // 運(yùn)行時(shí) panic(索引越界)

此時(shí)雖然分配了 slice 頭結(jié)構(gòu)(ptr/len/cap),但:

  • 底層數(shù)組指針為 nil
  • length 和 capacity 均為 0

3.3 make() 的初始化保證

make() 確保返回的對象立即可用:

s := make([]int, 5)
s[0] = 1          // 安全操作
ch := make(chan int, 5)
ch <- 1           // 不會(huì)阻塞
m := make(map[string]int)
m["key"] = 1      // 不會(huì) panic

初始化過程包括:

  • 為 slice 分配底層數(shù)組
  • 初始化 map 的哈希桶
  • 創(chuàng)建 channel 的環(huán)形緩沖區(qū)

四、編譯器優(yōu)化策略

4.1 逃逸分析的差異處理

new() 分配的對象可能被分配到棧上:

func localAlloc() *int {
    return new(int)  // 可能進(jìn)行棧分配
}

編譯器會(huì)在編譯期間決定對象是否需要分配到堆上:

// 如果發(fā)生逃逸,生成 runtime.newobject 調(diào)用
if escapeAnalysisResult.escapes {
    call = mkcall("newobject", ...)
} else {
    // 直接在棧上分配空間
}
  • 通過 -gcflags=“-m” 可查看具體逃逸決策
  • 棧分配完全繞過 mallocgc,顯著提升性能

而 make 創(chuàng)建的對象總是逃逸到堆:

func createSlice() []int {
    return make([]int, 10)  // 必須堆分配
}

4.2 初始化優(yōu)化

編譯器會(huì)對 new() 后的立即賦值進(jìn)行優(yōu)化:

p := new(int)
*p = 42
// 優(yōu)化為直接分配已初始化的內(nèi)存

五、典型平臺(tái)的匯編輸出驗(yàn)證

以 AMD64 平臺(tái)為例,觀察生成的機(jī)器碼:

//go tool compile -S test.go
MOVQ    $type.MyStruct(SB), AX  ;; 加載類型元數(shù)據(jù)
CALL    runtime.newobject(SB)   ;; 調(diào)用分配函數(shù)
  • 類型元數(shù)據(jù)在只讀段存儲(chǔ),保證多協(xié)程訪問安全
  • 最終調(diào)用約定遵循 Go 特有的 ABI 規(guī)范

六、實(shí)踐建議與模式選擇

6.1 選擇決策樹

是否創(chuàng)建引用類型?
├─ 是 → 必須使用 make()
└─ 否 → 是否需要指針?
       ├─ 是 → 使用 new()
       └─ 否 → 使用字面量初始化

6.2 性能考量

對于結(jié)構(gòu)體初始化,推薦直接使用值類型:

// 優(yōu)于 new(MyStruct)
var s MyStruct

當(dāng)需要明確的指針語義時(shí)再使用 new()

6.3 特殊使用模式

組合使用實(shí)現(xiàn)延遲初始化:

type LazyContainer struct {
    data *[]string
}
func (lc *LazyContainer) Get() []string {
    if lc.data == nil {
        lc.data = new([]string)
        *lc.data = make([]string, 0, 10)
    }
    return *lc.data
}

七、性能優(yōu)化啟示

1.盡量讓小型結(jié)構(gòu)體留在棧上

  • 控制結(jié)構(gòu)體大小,避免無意識(shí)逃逸

2.警惕大對象導(dǎo)致的 GC 壓力

  • 超過 32KB 的對象直接從堆分配

3.批量初始化替代多次 new()

  • 使用對象池或切片預(yù)分配降低開銷

八、從設(shè)計(jì)哲學(xué)理解差異

Go 語言通過 new 和 make 的分離體現(xiàn)了其類型系統(tǒng)的設(shè)計(jì)哲學(xué):

  • 明確性:強(qiáng)制開發(fā)者顯式處理引用類型的特殊初始化需求
  • 安全性:避免未初始化引用類型導(dǎo)致的運(yùn)行時(shí)錯(cuò)誤
  • 正交性:保持基本類型系統(tǒng)與引用類型系統(tǒng)的隔離

這種設(shè)計(jì)雖然增加了初學(xué)者的學(xué)習(xí)成本,但為大型工程提供了更好的可維護(hù)性和運(yùn)行時(shí)安全性。

通過對內(nèi)存分配機(jī)制、編譯器優(yōu)化策略和語言設(shè)計(jì)哲學(xué)的分析,我們可以清晰地認(rèn)識(shí)到:new() 是通用的內(nèi)存分配原語,而 make() 是針對引用類型的類型感知構(gòu)造器。理解這一區(qū)別有助于開發(fā)者寫出更符合 Go 語言設(shè)計(jì)思想的優(yōu)雅代碼。

到此這篇關(guān)于Golang中的new()和make()函數(shù)的文章就介紹到這了,更多相關(guān)Golang new()和make()函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • GO必知必會(huì)的常見面試題匯總

    GO必知必會(huì)的常見面試題匯總

    這篇文章主要為大家介紹了GO必知必會(huì)的常見面試題匯總
    2022-08-08
  • go語言優(yōu)雅地處理error工具及技巧詳解

    go語言優(yōu)雅地處理error工具及技巧詳解

    這篇文章主要為大家介紹了go語言優(yōu)雅地處理error工具及技巧詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • 詳解Golang中Channel的用法

    詳解Golang中Channel的用法

    如果說goroutine是Go語言程序的并發(fā)體的話,那么channels則是它們之間的通信機(jī)制。這篇文章主要介紹Golang中Channel的用法,需要的朋友可以參考下
    2020-11-11
  • GO中?分組聲明與array,?slice,?map函數(shù)

    GO中?分組聲明與array,?slice,?map函數(shù)

    這篇文章主要介紹了GO中?分組聲明與array,slice,map函數(shù),Go語言中,同時(shí)聲明多個(gè)常量、變量,或者導(dǎo)入多個(gè)包時(shí),可采用分組的方式進(jìn)行聲明,下面詳細(xì)介紹需要的小伙伴可以參考一下
    2022-03-03
  • go單例實(shí)現(xiàn)雙重檢測是否安全的示例代碼

    go單例實(shí)現(xiàn)雙重檢測是否安全的示例代碼

    這篇文章主要介紹了go單例實(shí)現(xiàn)雙重檢測是否安全,本文給大家分享雙重檢驗(yàn)示例代碼,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • GO語言 復(fù)合類型專題

    GO語言 復(fù)合類型專題

    這篇文章主要介紹了GO語言 復(fù)合類型的的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • Golang使用CGO與Plugin技術(shù)運(yùn)行加載C動(dòng)態(tài)庫

    Golang使用CGO與Plugin技術(shù)運(yùn)行加載C動(dòng)態(tài)庫

    這篇文章主要介紹了Golang使用CGO與Plugin技術(shù)運(yùn)行加載C動(dòng)態(tài)庫,Golang?程序在運(yùn)行時(shí)加載C動(dòng)態(tài)庫的技術(shù),跳過了Golang項(xiàng)目編譯階段需要鏈接C動(dòng)態(tài)庫的過程,提高了Golang項(xiàng)目開發(fā)部署的靈活性
    2022-07-07
  • go語言reflect.Type?和?reflect.Value?應(yīng)用示例詳解

    go語言reflect.Type?和?reflect.Value?應(yīng)用示例詳解

    這篇文章主要為大家介紹了go語言reflect.Type?和?reflect.Value?應(yīng)用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • Go語言常見錯(cuò)誤之a(chǎn)ny沒傳遞任何信息解決分析

    Go語言常見錯(cuò)誤之a(chǎn)ny沒傳遞任何信息解決分析

    Go語言,由于其高效強(qiáng)大的并行處理能力和優(yōu)雅簡單的設(shè)計(jì)哲學(xué),一直以來都是編程世界的寵兒,然而,對于一些Go新手和甚至熟悉Go的程序員也可能會(huì)遇到一個(gè)常見的錯(cuò)誤:?any沒傳遞任何信息,那么,如何規(guī)避這個(gè)錯(cuò)誤,本文將揭示其中的秘密
    2024-01-01
  • 基于Go語言實(shí)現(xiàn)猜謎游戲

    基于Go語言實(shí)現(xiàn)猜謎游戲

    這篇文章主要為大家詳細(xì)介紹了如何基于Go語言實(shí)現(xiàn)猜謎游戲,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)
    2023-09-09

最新評(píng)論