结构体中的struct{}造成的内存对齐

问题描述当

struct{} 作为其他 struct 最后一个字段时,需要填充额外的内存保证安全。代码如下:

type demo3 struct {
    c int32
    a struct{}
}

type demo4 struct {
    a struct{}
    c int32
}

func main() {
    fmt.Println(unsafe.Sizeof(demo3{})) // 8
    fmt.Println(unsafe.Sizeof(demo4{})) // 4
}

demo4{} 的大小为 4 字节,与字段 c 占据空间一致,而 demo3{} 的大小为 8 字节,即额外填充了 4 字节的空间。

我的疑问

我看到的解释是:
有指针指向该字段, 返回的地址将在结构体之外,如果此指针一直存活不释放对应的内存,就会有内存泄露的问题(该内存不因结构体释放而释放)

为什么额外填充了一些字节,就能保证内存安全?

最佳答案

我看到到解释是:

在目前的官方Go标准运行时的实现中,如果一个内存块被至少一个依然活跃的指针引用,那么这个内存块将不会被视作垃圾因而肯定不会被回收。 所以只要有一个活跃的指针存储着此非零size的结构体值的最后一个字段的越界地址,它将阻止垃圾收集器回收另一个内存块,从而可能导致内存泄漏。

为避免上述问题,标准的Go编译器会确保取一个非零size的结构体值的最后一个字段的地址时,绝对不会返回越出分配给此结构体值的内存块的地址。 Go标准编译器通过在需要时在结构体最后的零size字段之后填充一些字节来实现这一点。

如果一个结构体的全部字段的类型都是零size的(因此整个结构体也是零szie的),那么就不需要再填充字节,因为标准编译器会专门处理零size的内存块。

1年前 评论
讨论数量: 1

我看到到解释是:

在目前的官方Go标准运行时的实现中,如果一个内存块被至少一个依然活跃的指针引用,那么这个内存块将不会被视作垃圾因而肯定不会被回收。 所以只要有一个活跃的指针存储着此非零size的结构体值的最后一个字段的越界地址,它将阻止垃圾收集器回收另一个内存块,从而可能导致内存泄漏。

为避免上述问题,标准的Go编译器会确保取一个非零size的结构体值的最后一个字段的地址时,绝对不会返回越出分配给此结构体值的内存块的地址。 Go标准编译器通过在需要时在结构体最后的零size字段之后填充一些字节来实现这一点。

如果一个结构体的全部字段的类型都是零size的(因此整个结构体也是零szie的),那么就不需要再填充字节,因为标准编译器会专门处理零size的内存块。

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!