搜索
首页后端开发Golang解密Go:空结构
解密Go:空结构Sep 11, 2024 pm 12:30 PM

Decrypt Go: empty struct

在 Go 中,普通的结构体通常会占用一块内存。但是,有一种特殊情况:如果它是空结构,则其大小为零。这怎么可能,空结构有什么用?

本文首发于Medium MPP计划。如果您是Medium用户,请在Medium上关注我。非常感谢。

type Test struct {
    A int
    B string
}

func main() {
    fmt.Println(unsafe.Sizeof(new(Test)))
    fmt.Println(unsafe.Sizeof(struct{}{}))
}

/*
8
0
*/

空结构的秘密

特殊变量:zerobase

空结构是没有内存大小的结构。这种说法是正确的,但更准确地说,它实际上有一个特殊的起点:zerobase 变量。这是一个uintptr全局变量,占用8个字节。每当定义无数个 struct {} 变量时,编译器都会分配这个零基变量的地址。换句话说,在 Go 中,任何大小为 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)
}

// 0x58e360
// 0x58e360
// 0x58e360

空结构体的变量的内存地址都是相同的。这是因为编译器在编译过程中遇到这种特殊类型的内存分配时会分配&zerobase。这个逻辑在mallocgc函数中:

//go:linkname mallocgc  
func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {  
    ...
    if size == 0 {  
       return unsafe.Pointer(&zerobase)  
    }
    ...

这是 Empty 结构的秘密。通过这个特殊的变量,我们可以完成很多功能。

空结构和内存对齐

通常,如果空结构是较大结构的一部分,它不会占用内存。但是,有一种特殊情况,即空结构是最后一个字段;它会触发内存对齐。

示例

type A struct {
    x int
    y string
    z struct{}
}
type B struct {
    x int
    z struct{}
    y string
}

func main() {
    println(unsafe.Alignof(A{}))
    println(unsafe.Alignof(B{}))
    println(unsafe.Sizeof(A{}))
    println(unsafe.Sizeof(B{}))
}

/**
8
8
32
24
**/

当存在指向字段的指针时,返回的地址可能位于结构体之外,如果在释放结构体时未释放内存,则可能导致内存泄漏。因此,当空结构是另一个结构的最后一个字段时,为了安全起见,会分配额外的内存。如果空结构体位于开头或中间,则其地址与下一个变量相同。

type A struct {  
    x int  
    y string  
    z struct{}  
}  
type B struct {  
    x int  
    z struct{}  
    y string  
}  

func main() {  
    a := A{}  
    b := B{}  
    fmt.Printf("%p\n", &a.y)  
    fmt.Printf("%p\n", &a.z)  
    fmt.Printf("%p\n", &b.y)  
    fmt.Printf("%p\n", &b.z)  
}

/**
0x1400012c008
0x1400012c018
0x1400012e008
0x1400012e008
**/

空结构的用例

空struct struct{}存在的核心原因是为了节省内存。当您需要一个结构体但不关心其内容时,请考虑使用空结构体。 Go的核心复合结构如map、chan、slice都可以使用struct{}。

映射和结构{}

// Create map
m := make(map[int]struct{})
// Assign value
m[1] = struct{}{}
// Check if key exists
_, ok := m[1]

陈和结构{}

一个经典场景结合了channel和struct{},其中struct{}通常用作信号而不关心其内容。正如前面文章分析的那样,通道的本质数据结构是管理结构加上环形缓冲区。如果 struct{} 用作元素,则环形缓冲区为零分配。

chan 和 struct{} 一起使用的唯一用途是信号传输,因为空结构本身不能携带任何值。一般来说,它是在没有缓冲通道的情况下使用的。

// Create a signal channel
waitc := make(chan struct{})

// ...
goroutine 1:
    // Send signal: push element
    waitc 



<p>在这种情况下,struct{} 是绝对必要的吗?事实并非如此,节省的内存可以忽略不计。关键是不关心chan的元素值,所以使用struct{}。</p>

<h3>
  
  
  概括
</h3>

<ol>
<li>空结构体仍然是一个结构体,只是大小为 0。</li>
<li>所有空结构共享相同的地址:zerobase 的地址。</li>
<li>我们可以利用空结构体不占用内存的特性来优化代码,比如使用map来实现集合和通道。</li>
</ol>

<h3>
  
  
  参考
</h3>

<ol>
<li>空结构,戴夫·切尼</li>
<li>Go 最细节篇— struct{} 空结构体到底啥是啥?</li>
</ol>


          

            
        

以上是解密Go:空结构的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
如何编写模拟对象和存根以进行测试?如何编写模拟对象和存根以进行测试?Mar 10, 2025 pm 05:38 PM

本文演示了创建模拟和存根进行单元测试。 它强调使用接口,提供模拟实现的示例,并讨论最佳实践,例如保持模拟集中并使用断言库。 文章

如何定义GO中仿制药的自定义类型约束?如何定义GO中仿制药的自定义类型约束?Mar 10, 2025 pm 03:20 PM

本文探讨了GO的仿制药自定义类型约束。 它详细介绍了界面如何定义通用功能的最低类型要求,从而改善了类型的安全性和代码可重复使用性。 本文还讨论了局限性和最佳实践

您如何在GO中编写单元测试?您如何在GO中编写单元测试?Mar 21, 2025 pm 06:34 PM

本文讨论了GO中的编写单元测试,涵盖了最佳实践,模拟技术和有效测试管理的工具。

您如何使用PPROF工具分析GO性能?您如何使用PPROF工具分析GO性能?Mar 21, 2025 pm 06:37 PM

本文解释了如何使用PPROF工具来分析GO性能,包括启用分析,收集数据并识别CPU和内存问题等常见的瓶颈。

如何使用跟踪工具了解GO应用程序的执行流?如何使用跟踪工具了解GO应用程序的执行流?Mar 10, 2025 pm 05:36 PM

本文使用跟踪工具探讨了GO应用程序执行流。 它讨论了手册和自动仪器技术,比较诸如Jaeger,Zipkin和Opentelemetry之类的工具,并突出显示有效的数据可视化

解释GO反射软件包的目的。您什么时候使用反射?绩效有什么影响?解释GO反射软件包的目的。您什么时候使用反射?绩效有什么影响?Mar 25, 2025 am 11:17 AM

本文讨论了GO的反思软件包,用于运行时操作代码,对序列化,通用编程等有益。它警告性能成本,例如较慢的执行和更高的内存使用,建议明智的使用和最佳

您如何在go.mod文件中指定依赖项?您如何在go.mod文件中指定依赖项?Mar 27, 2025 pm 07:14 PM

本文讨论了通过go.mod,涵盖规范,更新和冲突解决方案管理GO模块依赖关系。它强调了最佳实践,例如语义版本控制和定期更新。

您如何在GO中使用表驱动测试?您如何在GO中使用表驱动测试?Mar 21, 2025 pm 06:35 PM

本文讨论了GO中使用表驱动的测试,该方法使用测试用例表来测试具有多个输入和结果的功能。它突出了诸如提高的可读性,降低重复,可伸缩性,一致性和A

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

仓库:如何复兴队友
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),