golang空结构创建后在同一个地址?

#前几天在论坛上看到一个这样的问题:

问题:分析一下,下面代码的输出是什么(判断a==c)的部分?

package main

import (
    "fmt"
    "runtime"
)

type obj struct{}

func main() {
    a := &obj{}
    fmt.Printf("%p\n", a)
    c := &obj{}
    fmt.Printf("%p\n", c)
    fmt.Println(a == c)
}

很多人可能一看,a和c完全是2个不同的对象实例,便认为a和c具备不同的内存地址,故而判断a==c的结果为false。

但是我们看一下实际输出:

0x11a6c10
0x11a6c10
true

问题:为什么变量 a 和 c ,内存地址是一样的?

这里原文将逃逸和这个新建struct对象的问题混了,因为在新建对象时调用了 runtime 包的 newobject 函数。而 newobject 函数其实本质上会调用 runtime 包内的 mallocgc 函数。

这个函数有点特别:

如果要分配内存的变量不占用实际内存,则直接用 golang 的全局变量 zerobase 的地址。而我们的变量 a 和 变量 c 有一个共同特点,就是它们是“空 struct”,空 struct 是不占用内存空间的。

// Allocate an object of size bytes.
// Small objects are allocated from the per-P cache's free lists.
// Large objects (> 32 kB) are allocated straight from the heap.
func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
	if gcphase == _GCmarktermination {
		throw("mallocgc called with gcphase == _GCmarktermination")
	}

  // 关键部分,如果要分配内存的变量不占用实际内存,则直接用 golang 的全局变量 zerobase 的地址。
	if size == 0 {
		return unsafe.Pointer(&zerobase)
	}

  // ...
}

所以,a 和 c 是空 struct,在做内存分配的时候,使用了 golang 内部全局私有变量 zerobase 的内存地址。

所以导致了最后判断时地址是一样的。

同样如果我们放弃fmt包,通过println去打地址,也是有同一个问题

package main

import (
    "fmt"
    "runtime"
)

type obj struct{}

func main() {
	a := &obj{}
	// fmt.Println(a)
	println(a)
	b := &obj{}
	println(b)
	// fmt.Println(b)
	println(a == b)
}

我们看结果

0xc000044767
0xc000044767
true
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值