• go语言之内存对齐


    之所以要了解内存对齐,本质也是为了提高程序运行效率,也是为了更好地优化内存

    对齐系数

    在这里插入图片描述

    对齐系数就是为了确定变量的内存地址的,内存地址必须得是对齐系数的整倍数

    在这里插入图片描述

    这里面我们看下基本类型的对齐系数都是多少:

    package main
    
    import (
    	"fmt"
    	"unsafe"
    )
    
    func main() {
    
    	fmt.Printf("bool 长度: %d, 内存系数: %d\n", unsafe.Sizeof(bool(true)), unsafe.Alignof(bool(true)))
    	fmt.Printf("byte 长度: %d, 内存系数: %d\n", unsafe.Sizeof(byte(0)), unsafe.Alignof(byte(0)))
    	fmt.Printf("int 长度: %d, 内存系数: %d\n", unsafe.Sizeof(int(0)), unsafe.Alignof(int(0)))
    	fmt.Printf("int8 长度: %d, 内存系数: %d\n", unsafe.Sizeof(int8(0)), unsafe.Alignof(int8(0)))
    	fmt.Printf("int16 长度: %d, 内存系数: %d\n", unsafe.Sizeof(int16(0)), unsafe.Alignof(int16(0)))
    	fmt.Printf("int32 长度: %d, 内存系数: %d\n", unsafe.Sizeof(int32(0)), unsafe.Alignof(int32(0)))
    	fmt.Printf("int64 长度: %d, 内存系数: %d\n", unsafe.Sizeof(int64(0)), unsafe.Alignof(int64(0)))
    	fmt.Printf("string 长度: %d, 内存系数: %d\n", unsafe.Sizeof("abc"), unsafe.Alignof("abc"))
    	fmt.Printf("float32 长度: %d, 内存系数: %d\n", unsafe.Sizeof(float32(1.0)), unsafe.Alignof(float32(1.0)))
    	fmt.Printf("float64 长度: %d, 内存系数: %d\n", unsafe.Sizeof(float64(1.0)), unsafe.Alignof(float64(1.0)))
    	i := 10.0
    	fmt.Printf("指针 长度: %d, 内存系数: %d\n", unsafe.Sizeof(&i), unsafe.Alignof(&i))
    	ii := map[string]int{"a": 1}
    	fmt.Printf("指针 长度: %d, 内存系数: %d\n", unsafe.Sizeof(&ii), unsafe.Alignof(&ii))
    
    }
    
    
    • 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

    结果输出:

    go run memaddrdemo.go
    bool 长度: 1, 内存系数: 1
    byte 长度: 1, 内存系数: 1
    int 长度: 8, 内存系数: 8
    int8 长度: 1, 内存系数: 1
    int16 长度: 2, 内存系数: 2
    int32 长度: 4, 内存系数: 4
    int64 长度: 8, 内存系数: 8
    string 长度: 16, 内存系数: 8
    float32 长度: 4, 内存系数: 4
    float64 长度: 8, 内存系数: 8
    指针 长度: 8, 内存系数: 8
    指针 长度: 8, 内存系数: 8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这里面我们重点关注一下为什么string的内存系数是8,长度是16

    string底层是一个结构体,通过反射我们看下它的组成部分:

    type StringHeader struct {
    	Data uintptr
    	Len  int
    }
    
    • 1
    • 2
    • 3
    • 4

    它主要有两部分组成:1 是指针,二是Len

    指针的长度是8,int的长度在64位机器也是8,那么其长度就是16.但是结构体的对齐系数下面会详细去讲,是结构体成员最大对齐系数,那么就是max(8,8) = 8,所以string的对齐系数是8,但是长度是16

    结构体对齐

    结构体对齐需要考虑两部分,一部分是结构体的内部对齐,也就是要考虑结构体的成员大小和成员的对齐系数,另一部分就是结构体长度填充,考虑系统字长

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fkZrgaOP-1660488648242)(file:///Users/kason/Library/Application%20Support/marktext/images/2022-08-14-20-42-35-image.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mTebWrXU-1660488648242)(file:///Users/kason/Library/Application%20Support/marktext/images/2022-08-14-20-44-08-image.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FNat3TT5-1660488648242)(file:///Users/kason/Library/Application%20Support/marktext/images/2022-08-14-20-44-31-image.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OYwI1Guq-1660488648242)(file:///Users/kason/Library/Application%20Support/marktext/images/2022-08-14-20-51-36-image.png)]

    在这里结构体最大成员长度就是string这个成员的长度是16个字节,系统字长8个字节(64位),所以结构体的长度就需要是min(16,8)=8的整数倍。因此你会看到下图中的补齐0的部分。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GmhU9lR1-1660488648242)(file:///Users/kason/Library/Application%20Support/marktext/images/2022-08-14-22-45-06-image.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fzk8Z32l-1660488648242)(file:///Users/kason/Library/Application%20Support/marktext/images/2022-08-14-20-52-03-image.png)]

    其实我们针对上述结构体的定义,我们看到bool之后和string之间其实浪费了大量的空间,那么我们可以通过调整顺序进行优化,将c init16定义在b string之前,就可以节约空间。节省空间如下所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zkjp3n2I-1660488648243)(file:///Users/kason/Library/Application%20Support/marktext/images/2022-08-14-20-57-32-image.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8dZBgOZu-1660488648243)(file:///Users/kason/Library/Application%20Support/marktext/images/2022-08-14-21-00-04-image.png)]

    围绕着上述的问题:

    首先string的对齐系数为什么是8, 因为string本身是结构体,里面一个指针,一个int的len,它的对齐系数其实就是string结构体最大成员的对齐系数,就是8

    刚才的DEMO结构体对齐系数就是max(1, 8, 2) = 8

    结构体对齐之特殊点:空结构体对齐

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-41DQ2nUm-1660488648243)(file:///Users/kason/Library/Application%20Support/marktext/images/2022-08-14-21-01-10-image.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AWOEHPID-1660488648243)(file:///Users/kason/Library/Application%20Support/marktext/images/2022-08-14-21-06-00-image.png)]

    内存对齐总结

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EqW4NIh0-1660488648243)(file:///Users/kason/Library/Application%20Support/marktext/images/2022-08-14-21-05-30-image.png)]

  • 相关阅读:
    数据结构之树和二叉树的基本概念,二叉树遍历算法的实现
    【JS】JavaScript入门笔记第一弹~
    Java-基于SSM的图书书城管理系统
    汇编基础知识
    【C++】类和对象(上)
    微信小程序注册指引
    Java 图书管理系统
    华为机试_HJ81 字符串字符匹配【简单】【收藏!】
    Jmeter+Ant+Git/SVN+Jenkins实现持续集成接口测试,一文精通(一)
    设计模式-单例模式
  • 原文地址:https://blog.csdn.net/zhangkai1992/article/details/126337844