阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Golang make和new的区别及实现原理详解

274次阅读
没有评论

共计 2722 个字符,预计需要花费 7 分钟才能阅读完成。

导读 在 Go 语言中,有两个比较雷同的内置函数,分别是 new 和 make 方法,二者都可以用来分配内存,那他们有什么区别呢?下面我们就从底层来分析一下二者的不同。感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助
前言

在 Go 语言中,有两个比较雷同的内置函数,分别是 new 和 make 方法,二者都可以用来分配内存,那他们有什么区别呢?对于初学者可能会觉得有点迷惑,尤其是在掌握不牢固的时候经常遇到 panic,下面我们就从底层来分析一下二者的不同。感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

new 的使用

new 可以对类型进行内存创建和初始化,其返回值是所创建类型的指针引用,这是与 make 函数的区别之一。我们通过一个示例代码看下:

func main() {
    var a *int
    fmt.Println(a) // nil
    *a = 123 //panic
    fmt.Println(a)
}

通过上面代码可以看出,当我们通过 var 声明一个变量后打印后输出 nil,当我们给这个变量赋值的时候会报错:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x10a9043]

综上可以总结出初始化一个指针变量,其值为 nil,nil 的值是不能直接赋值的。

既然我们知道了没有为其分配内存,那么我们使用 new 分配一个吧。代码修改后:

func main() {
    var a *int
    a = new(int)
    fmt.Printf("a type is :%T,a point value is :%v,a value is:%v,a size is: %v\n", a, a, *a, unsafe.Sizeof(a))
    //a type is :*int,a point value is :0xc00001a0a0,a value is:0,a size is: 8
    *a = 123
    fmt.Printf("a type is :%T,a point value is :%v,a value is:%v,a size is: %v\n", a, a, *a, unsafe.Sizeof(a))
    //a type is :*int,a point value is :0xc00001a0a0,a value is:123,a size is: 8
}

通过以上示例我们可以看到 new 其返回一个指向新分配的类型为 int 的指针,指针值为 0xc00001a0a0,这个指针指向的内容的值为零(zero value)。通过 new 进行内存分配就可以对其进行赋值。

底层实现

new 函数的签名如下:

func new(Type) *Type

Type 是指变量的类型,可以看到 new 会根据变量类型返回一个指向该类型的指针。

底层调用的是 runtime.newobject 申请内存空间:

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

通过调用 mallocgc 在堆上按照 typ.size 的大小申请内存,因此 new 只会为结构体申请一块内存空间,不会为结构体中的指针类型申请内存空间。

make 的使用

make 函数也是用于内存分配的,但是和 new 不同,仅支持 slice、map、channel 三种数据类型的内存创建,其返回值是所创建类型的本身,而不是新的指针引用。

注意:这三种类型都是引用类型,所以没必要返回他们的指针了,必须得初始化,但是不是设置为零值。

我们通过一个示例看一下:

func test()  {var s *[]int
    fmt.Printf("s: %p %#v \n", &s, s) //s: 0xc00000e028 (*[]int)(nil)
    s = new([]int)
    fmt.Printf("s: %p %#v \n", &s, s) //s: 0xc00000e028 &[]int(nil)
    (*s)[0] = 8
    fmt.Printf("s: %p %#v \n", &s, s) //panic: runtime error: index out of range [0] with length 0
}

我们先用 new 进行初始化,会给引用类型初始化为 nil,nil 是不能直接赋值的。下面改为 make。

func test()  {var s = make([]int, 5)
    fmt.Printf("s: %p %#v \n", &s, s) //s: 0xc00000c060 []int{0, 0, 0, 0, 0}
    s[0] = 8
    fmt.Printf("s: %p %#v \n", &s, s) //s: 0xc00000c060 []int{8, 0, 0, 0, 0}
}

通过以上示例输出我们可以看到,make 不仅可以开辟一个内存,还能给这个内存的类型初始化其零值。同理,对于 map、channel 也是同样的效果。

底层实现

make 函数的签名如下:

func make(t Type, size ...IntegerType) Type

可以看到 make 返回的是复合类型本身。

make 在申请 slice 内存时,底层调用的是 runtime.makeslice,

func makeslice(et *_type, len, cap int) unsafe.Pointer {mem, overflow := math.MulUintptr(et.size, uintptr(cap))
    if overflow || mem > maxAlloc || len  cap {mem, overflow := math.MulUintptr(et.size, uintptr(len))
        if overflow || mem > maxAlloc || len 

可以看到 makeslice 申请内存底层调用的也是 mallocgc,首先通过 MulUintptr 根据容量 cap 乘以 type.siz 计算出所需要内存大小,然后再分配所需内存,make 为 map 和 channel 申请内存底层分别是 runtime.makemap_small,runtime.makechan,也是同样调用 mallocgc。

总结
  • make 和 new 都是 golang 用来分配内存的函数,且在堆上分配内存,make 即分配内存,也初始化内存。new 只是将内存清零,并没有初始化内存。
  • make 返回的还是引用类型本身;而 new 返回的是指向类型的指针。
  • make 只能用来分配及初始化类型为 slice,map,channel 的数据;new 可以分配任意类型的数据。
  • 到此这篇关于深入理解 Golang make 和 new 的区别及实现原理的文章就介绍到这了

    阿里云 2 核 2G 服务器 3M 带宽 61 元 1 年,有高配

    腾讯云新客低至 82 元 / 年,老客户 99 元 / 年

    代金券:在阿里云专用满减优惠券

    正文完
    星哥玩云-微信公众号
    post-qrcode
     0
    星锅
    版权声明:本站原创文章,由 星锅 于2024-07-24发表,共计2722字。
    转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
    【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
    阿里云-最新活动爆款每日限量供应
    评论(没有评论)
    验证码
    【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

    星哥玩云

    星哥玩云
    星哥玩云
    分享互联网知识
    用户数
    4
    文章数
    19351
    评论数
    4
    阅读量
    7982175
    文章搜索
    热门文章
    星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

    星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

    星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
    星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

    星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

    星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
    我把用了20年的360安全卫士卸载了

    我把用了20年的360安全卫士卸载了

    我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
    再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

    再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

    再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
    飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

    飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

    飞牛 NAS 中安装 Navidrome 音乐文件中文标签乱码问题解决、安装 FntermX 终端 问题背景 ...
    阿里云CDN
    阿里云CDN-提高用户访问的响应速度和成功率
    随机文章
    CSDN,你是老太太喝粥——无齿下流!

    CSDN,你是老太太喝粥——无齿下流!

    CSDN,你是老太太喝粥——无齿下流! 大家好,我是星哥,今天才思枯竭,不写技术文章了!来吐槽一下 CSDN。...
    Prometheus:监控系统的部署与指标收集

    Prometheus:监控系统的部署与指标收集

    Prometheus:监控系统的部署与指标收集 在云原生体系中,Prometheus 已成为最主流的监控与报警...
    星哥带你玩飞牛NAS-7:手把手教你免费内网穿透-Cloudflare tunnel

    星哥带你玩飞牛NAS-7:手把手教你免费内网穿透-Cloudflare tunnel

    星哥带你玩飞牛 NAS-7:手把手教你免费内网穿透 -Cloudflare tunnel 前言 大家好,我是星...
    星哥带你玩飞牛NAS-1:安装飞牛NAS

    星哥带你玩飞牛NAS-1:安装飞牛NAS

    星哥带你玩飞牛 NAS-1:安装飞牛 NAS 前言 在家庭和小型工作室场景中,NAS(Network Atta...
    星哥带你玩飞牛NAS-16:飞牛云NAS换桌面,fndesk图标管理神器上线!

    星哥带你玩飞牛NAS-16:飞牛云NAS换桌面,fndesk图标管理神器上线!

      星哥带你玩飞牛 NAS-16:飞牛云 NAS 换桌面,fndesk 图标管理神器上线! 引言 哈...

    免费图片视频管理工具让灵感库告别混乱

    一言一句话
    -「
    手气不错
    小白也能看懂:什么是云服务器?腾讯云 vs 阿里云对比

    小白也能看懂:什么是云服务器?腾讯云 vs 阿里云对比

    小白也能看懂:什么是云服务器?腾讯云 vs 阿里云对比 星哥玩云,带你从小白到上云高手。今天咱们就来聊聊——什...
    星哥带你玩飞牛NAS硬件02:某鱼6张左右就可拿下5盘位的飞牛圣体NAS

    星哥带你玩飞牛NAS硬件02:某鱼6张左右就可拿下5盘位的飞牛圣体NAS

    星哥带你玩飞牛 NAS 硬件 02:某鱼 6 张左右就可拿下 5 盘位的飞牛圣体 NAS 前言 大家好,我是星...
    如何安装2026年最强个人助理ClawdBot、完整安装教程

    如何安装2026年最强个人助理ClawdBot、完整安装教程

    如何安装 2026 年最强个人助理 ClawdBot、完整安装教程 一、前言 学不完,根本学不完!近期,一款名...
    还在找免费服务器?无广告免费主机,新手也能轻松上手!

    还在找免费服务器?无广告免费主机,新手也能轻松上手!

    还在找免费服务器?无广告免费主机,新手也能轻松上手! 前言 对于个人开发者、建站新手或是想搭建测试站点的从业者...
    12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换,告别多工具切换

    12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换,告别多工具切换

    12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换...