认识Go语言空结构体

结构体常识

在Go语言中,结构体(struct)是一种用户自定义的数据类型,用于封装一组相关的字段(field)。结构体可以包含不同类型的字段,并允许你创建具有特定属性和行为的自定义类型。

type 结构体名称 struct {  
    字段1 类型1  
    字段2 类型2  
    ...  
    字段N 类型N  
}

结构体名称是你为结构体定义的名称,字段是结构体的成员变量,类型是字段的数据类型。
golang 正常的 struct 就是普通的一个内存块,必定是占用一小块内存的,并且结构体的大小是要经过边界,长度的对齐的。

// 类型变量对齐到 8 字节;
type Tp struct {
    a uint16
    b uint32
}

按照内存对齐规则,这个结构体占用 8 个字节的内存。

空结构体

基本概念

空结构体(empty struct)是一个没有包含任何字段的结构体类型。它通常用于需要一个占位符类型,但又不需要存储任何实际数据的情况。空结构体通常写作 struct{}。
空结构体:

var s struct{}
// 变量 size 是 0 ;
fmt.Println(unsafe.Sizeof(s))

该空结构体的变量占用内存 0 字节。

空结构体有几个用途:

  • 作为占位符:在需要一个类型,但不需要存储任何数据时,可以使用空结构体。
  • 作为映射的键:当你想使用一个简单的、不占用太多内存的类型作为映射(map)的键时,空结构体是一个好选择。
  • 作为信号量或标志:在某些同步原语中,可以使用通道(channel)来传递空结构体作为信号。
  • 节省内存:当你需要一个类型,但内存使用是一个关键因素时,空结构体不占用任何额外的空间(除了可能的类型信息,这取决于运行时实现)。

本质上来讲,使用空结构体的初衷只有一个:节省内存,但是更多的情况,节省的内存其实很有限,这种情况使用空结构体的考量其实是:根本不关心结构体变量的值。
需要注意的是,虽然空结构体不占用任何额外的空间来存储字段,但在某些情况下(例如作为映射的键或通道的元素),它们仍然会占用一些内存来标识唯一的实例。这取决于Go运行时的具体实现。但相对于其他包含实际字段的结构体,空结构体在内存使用上是非常轻量级的。

特殊变量:zerobase

空结构体是没有内存大小的结构体。这句话是没有错的,但是更准确的来说,其实是有一个特殊起点的,那就是 zerobase 变量,这是一个 uintptr 全局变量,占用 8 个字节。当在任何地方定义无数个 struct {} 类型的变量,编译器都只是把这个 zerobase 变量的地址给出去。换句话说,在 golang 里面,涉及到所有内存 size 为 0 的内存分配,那么就是用的同一个地址 &zerobase 。

package main

import "fmt"

type emptyStruct struct {}

func main() {
    a := struct{}{}
    b := struct{}{}
    c := emptyStruct{}

    fmt.Printf("%p\n", &a)
    fmt.Printf("%p\n", &b)
    fmt.Printf("%p\n", &c)
}
dlv打印:
(dlv) p &a
(*struct {})(0x57bb60)
(dlv) p &b
(*struct {})(0x57bb60)
(dlv) p &c
(*main.emptyStruct)(0x57bb60)
(dlv) p &runtime.zerobase
(*uintptr)(0x57bb60)

空结构体的变量的内存地址都是一样的。

内存管理特殊处理

编译器在编译期间,识别到 struct {} 这种特殊类型的内存分配,会统统分配出 runtime.zerobase 的地址出去,这个代码逻辑是在 mallocgc 函数里面:

func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
    // 分配 size 为 0 的结构体,把全局变量 zerobase 的地址给出去即可;
    if size == 0 {
        return unsafe.Pointer(&zerobase)
    }
    // ...

golang 使用 mallocgc 分配内存的时候,如果 size 为 0 的时候,统一返回的都是全局变量 zerobase 的地址。

参考:https://zhuanlan.zhihu.com/p/351176221

  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值