【Go】make和new的区别
点击阅读更多查看文章内容
make和new的区别
new
1 | package main |
执行以上代码会发生panic
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x1 addr=0x0 pc=0x34bffa]
new的函数声明
1 | func new(Type) *Type |
Type是指变量的类型,**new会根据变量类型返回一个指向该类型的指针**。
new底层调用的是runtime.newobject申请内存空间
1 | func newobject(typ *_type) unsafe.Pointer { |
newobject的底层调用mallocgc在堆上按照typ.size的大小申请内存,因此**new只会为结构体Student申请一片内存空间,不会为结构体中的指针age申请内存空间**,所以 *(s.age) 的解引用操作就因为访问无效的内存空间而出现panic。
对于结构体指针,工作中一般使用s:=&Stuent{age:=new(int)}的方式赋值,这样能够清晰的知道结构体中的每一个字段是什么,避免不必要的错误!
make
1 | package main |
以上程序在运行时也会出现panic,slice的底层实现为:
1 | type slice struct { |
这就和上面的例子一样了,**new只会为结构体slice申请内存,而不会为当中的array字段申请内存,因此用(nums)[0]取值会发生panic。*
如果需要对slice、map、channel进行内存申请,则必须使用make申请内存,下面看一下make函数声明
1 | func make(t Type, size ...IntegerType) Type |
可以看到make返回的是复合类型本身,将错误代码修改如下
1 | package main |
分析make的实现
1 | func makeslice(et *_type, len, cap int) unsafe.Pointer { |
可以看到makeslice申请内存底层调用的也是mallocgc,从这点看和new一样,但是细看new中mallocgc第一个参数(申请内存大小)用的是type.size,而make中的mallocgc第一个参数是mem,从MulUintptr源码中可以看出mem是slice的容量cap乘以type.size,因此使用makeslice可以成功的为切片申请内存。
make为map和channel申请内存底层分别是runtime.makemap_small,runtime.makechan,也是同样调用mallocgc,这里就不继续讨论了
更进一步举个例子,以下示例中,a的内存占用为8因为new([]int) 创建一个指向 []int 类型的指针,并返回该指针。指针的大小是 8 字节。 *a解指针得到的就是指针实际指向的切片包含三部分ptr:指向底层数组的指针(8 字节)。len:切片的长度(8 字节)。cap:切片的容量(8 字节)。一共24字节,b的内存占用就是24字节因为make([]int, 0)返回的就是切片本身
1 | func main() { |
make和new的区别
相同点
- 都是Go语言中用于内存申请的关键字
- 底层都是通过mallocgc申请内存
不同点
make返回点是复合结构体本身而new返回的是指向变量内存的指针make只能为channel,slice,map申请内存空间
【Go】make和new的区别

