• golang 内存对齐


    转, 原文:https://www.jianshu.com/p/29ac532e7c96

    type SizeOfE struct {
        A byte  // 1
        C byte  // 1
        B int64 // 8    
    }

    内存分布图:

    package main
    
    import (
      "log"
      "unsafe"
    )
    
    func main() {
      type pgid int64
      type page struct {
        id       pgid
        ptr      uintptr
        flags    uint16
        count    uint16
        overflow uint32
      }
      log.Println(int(unsafe.Sizeof(((*page)(nil)).id)))
      log.Println(int(unsafe.Sizeof(((*page)(nil)).flags)))
      log.Println(int(unsafe.Sizeof(((*page)(nil)).count)))
      log.Println(int(unsafe.Sizeof(((*page)(nil)).overflow)))
      log.Println(int(unsafe.Offsetof(((*page)(nil)).ptr)))
    }
    

      

    https://www.jianshu.com/p/49f7e6f56568?utm_source=desktop&utm_medium=timeline

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

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

    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内置类型占用内存大小



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

    Alignof 函数

    Alignof返回一个类型的对齐值,也可以叫做对齐系数或者对齐倍数。对齐值是一个和内存对齐有关的值,合理的内存对齐可以提高内存读写的性能。

    func main() {
        var b bool
        var i8 int8
        var i16 int16
        var i64 int64
    
        var f32 float32
    
        var s string
    
        var m map[string]string
    
        var p *int32
    
        fmt.Println(unsafe.Alignof(b))   // 1
        fmt.Println(unsafe.Alignof(i8))  // 1
        fmt.Println(unsafe.Alignof(i16)) // 2
        fmt.Println(unsafe.Alignof(i64)) // 8
        fmt.Println(unsafe.Alignof(f32)) // 4
        fmt.Println(unsafe.Alignof(s))   // 8
        fmt.Println(unsafe.Alignof(m))   // 8
        fmt.Println(unsafe.Alignof(p))   // 8
    }
    
    

    从以上例子的输出,可以看到,对齐值一般是2^n,最大不会超过8(原因见下面的内存对齐规则)。Alignof的函数定义和Sizeof基本上一样。这里需要注意的是每个人的电脑运行的结果可能不一样,大同小异。

    func Alignof(x ArbitraryType) uintptr
    

    获取对齐值还可以使用反射包的函数,也就是说:unsafe.Alignof(x)等价于reflect.TypeOf(x).Align()。



    作者:Gopherzhang
    链接:https://www.jianshu.com/p/49f7e6f56568
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    洛谷 P4071 [SDOI2016]排列计数
    问题 G: 【一本通提高同余问题】计算器
    问题 A: 【一本通提高组合数学】Bullcow 牡牛和牝牛
    浅谈卢卡斯定理(非扩展)
    2019西安联训B层 Day 6练习题 问题 C: 扩展欧几里得
    react使用lazy()和Suspense实现根据路由进行代码分割
    react-loadable 使用高阶组件动态import组件,实现代码分割(code-splitting)
    react angular vue流行度对比
    react 服务端渲染(ssr) 框架 Next.js
    超级字符串内class正则匹配替换 可以用于css modules
  • 原文地址:https://www.cnblogs.com/oxspirt/p/14676472.html
Copyright © 2020-2023  润新知