好好爱自己!

unsafe.Sizeof 和 unsafe.Offsetof 的理解

Alignof返回的对齐数是结构体中最大元素所占的内存数,不超过8,

 

 

参考:https://studygolang.com/articles/21827

 

 

unsafe.Sizeof 和 unsafe.Offsetof 的理解

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package main
  
 import (
     "fmt"
     "unsafe"
     "log"
 )
  
 func main() {
  
     var x struct {
         a bool
         b int16
         c []int
     }
  
     /**
     unsafe.Offsetof 函数的参数必须是一个字段 x.f, 然后返回 f 字段相对于 x 起始地址的偏移量, 包括可能的空洞.
     */
  
     /**
     uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.b)
     指针的运算
     */
     // 和 pb := &x.b 等价
  
     pb := (*int16)(unsafe.Pointer(uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.b)))
     *pb = 42
     fmt.Println(x.b) // "42"
      
     //m := x{}
     x.a = true
     x.b = 132
     x.c = []int{1,2,2,3,4}
     log.Println("Sizeof:")
     log.Println(unsafe.Sizeof(x.a))
     log.Println(unsafe.Sizeof(x.b))
     log.Println(unsafe.Sizeof(x.c))
     log.Println(unsafe.Sizeof(x))
     log.Println("Offsetof:")
     log.Println(unsafe.Offsetof(x.a))
     log.Println(unsafe.Offsetof(x.b))
     log.Println(unsafe.Offsetof(x.c))
     log.Println("ttt:")
     type SizeOfE struct {
       A byte  // 1
       C byte  // 1 //调换一下B C的顺序,择Sizeof 整个结构体的大小由24变为了16
       B int64 // 8
    }
    var tt SizeOfE
    log.Println(unsafe.Sizeof(SizeOfE{}))
    log.Println(unsafe.Sizeof(tt.A))
    log.Println(unsafe.Sizeof(tt.B))
    log.Println(unsafe.Sizeof(tt.C))
    log.Println(unsafe.Sizeof(tt))
    log.Println("AlignOf:")
    log.Println(unsafe.Alignof(tt.A))
    log.Println(unsafe.Alignof(tt.B))
    log.Println(unsafe.Alignof(tt.C))
    log.Println(unsafe.Alignof(tt))
 
}

  ------------------------

https://www.jianshu.com/p/29ac532e7c96

如何得到一个对象所占内存大小?

fmt.Println(unsafe.Sizeof(int64(0))) // "8"

type SizeOfA struct {
    A int
}
unsafe.Sizeof(SizeOfA{0}) // 8

type SizeOfC struct {
    A byte  // 1字节
    C int32 // 4字节
}
unsafe.Sizeof(SizeOfC{0, 0})    // 8
unsafe.Alignof(SizeOfC{0, 0}) // 4
结构体中A byte占1字节,C int32占4字节. SizeOfC占8字节

内存对齐:

为何会有内存对齐?1.并不是所有硬件平台都能访问任意地址上的任意数据。2.性能原因 访问未对齐的内存,处理器需要做两次内存访问,而对齐的内存只需访问一次。
上面代码SizeOfC中元素一共5个字节,而实际结构体占8字节
是因为这个结构体的对齐倍数Alignof(SizeOfC) = 4.也就是说,结构体占的实际大小必须是4的倍数,也就是8字节。

type SizeOfD struct {
    A byte
    B [5]int32
}
unsafe.Sizeof(SizeOfD{})   // 24
unsafe.Alignof(SizeOfD{})  // 4

Alignof返回的对齐数是结构体中最大元素所占的内存数,不超过8,如果元素是数组那么取数组类型所占的内存值而不是整个数组的值

type SizeOfE struct {
    A byte  // 1
    B int64 // 8
    C byte  // 1
}
unsafe.Sizeof(SizeOfE{})    // 24
unsafe.Alignof(SizeOfE{}) // 8

SizeOfE中,元素的大小分别为1,8,1,但是实际结构体占24字节,远超元素实际大小,因为内存对齐原因,最开始分配的8字节中包含了1字节的A,剩余的7字节不足以放下B,又为B分配了8字节,剩余的C独占再分配的8字节。

type SizeOfE struct {
    A byte  // 1
    C byte  // 1
    B int64 // 8    
}
unsafe.Sizeof(SizeOfE{})    // 16
unsafe.Alignof(SizeOfE{}) // 8

换一种写法,把A,C放到上面,B放到下面。这时SizeOfE占用的内存变为了16字节。因为首先分配的8字节足以放下A和C,省去了8字节的空间。
上面一个结构体中元素的不同顺序足以导致内存分配的巨大差异。前一种写法产生了很多的内存空洞,导致结构体不够紧凑,造成内存浪费。

下面我们来看一下结构体中元素的内存布局:

unsafe.Offsetof:返回结构体中元素所在内存的偏移量

type SizeOfF struct {
    A byte
    C int16
    B int64
    D int32
}
unsafe.Offsetof(SizeOfF{}.A) // 0
unsafe.Offsetof(SizeOfF{}.C) // 2
unsafe.Offsetof(SizeOfF{}.B) // 8
unsafe.Offsetof(SizeOfF{}.D) // 16

下图为内存分布图:


SizeOfF 内存布局图

蓝色区域是元素实际所占内存,灰色为内存空洞。

下面总结一下go语言中各种类型所占内存大小(x64环境下):

X64下1机器字节=8字节


Golang内置类型占用内存大小

总结一下:

从例子中可以看出,结构体中元素不同顺序的排列会导致内存分配的极大差异,不好的顺序会产生许多的内存空洞,造成大量内存浪费。
虽然这几个函数都在unsafe包中,但是他们并不是不安全的。在需要优化内存空间时这几个函数非常有用。



作者:郭老汉
链接:https://www.jianshu.com/p/29ac532e7c96
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
posted @   立志做一个好的程序员  阅读(832)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
历史上的今天:
2018-04-16 编译php ./configure命令enable和with有什么区别
2018-04-16 php自己编译安装后,再给这个编译安装的php版本添加拓展模块的处理办法。

不断学习创作,与自己快乐相处

点击右上角即可分享
微信分享提示