zoukankan      html  css  js  c++  java
  • 总结一下内存对齐学习

    什么是内存对齐

    以一个例子来说明,以64位系统为例

    type test struct {
    	a int32
    	b byte
    }
    
    func main() {
    	fmt.Println(unsafe.Sizeof(test{})) // 8
    }
    

    理论上int32占4个字节,byte占一个字节,test结构体应该占5个字节才对。但实际上占了8个字节,这就是进行了字节对齐。

    为什么会出现字节对齐

    现代计算机中内存空间都是按照 byte 划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但是实际的RAM内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数,这和RAM的存储原理有关。感兴趣可以去看这个视频。

    尽管内存是以字节为单位,但是大部分处理器并不是按字节块来存取内存的。它一般会以2字节,4字节(32位),8字节(64位),16字节甚至32字节为单位来存取内存,我们将上述这些存取单位称为内存存取粒度.

    内存存取粒度又称 对齐粒度(也叫对齐模数) 或称 寄存器宽度 或称 机器字长 或称 总线宽度 。gcc中默认#pragma pack(4),可以通过预编译命令#pragma pack(n),n = 1,2,4,8,16来改变这一系数。

    假如没有内存对齐机制,数据可以任意存放,现在一个int变量存放在从地址1开始的连续的4个字节地址中,该处理器去取数据时,要先从0地址开始读取第一个4字节块,剔除不想要的字节(0地址),然后从地址4开始读取下一个4字节块,同样剔除不要的数据(5,6,7地址),最后留下的两块数据合并放入寄存器。这会多做很多工作。所以就出现了对齐机制。

    建议看完上面的视频再来看下面的例子。

    对齐规则

    go语言中对齐规则和c语言的一样。 下面所有的描述都是对64位来说。

    • 对于简单类型,如果该类型大小超过8个字节,用8个字节对齐;小于8个字节按该类型的大小对齐,即按小的对齐

    • 对于结构体类型,它的默认对齐方式就是它的所有成员使用的对齐参数中最大的一个,这样在成员是复杂类型时,可以最小化长度。

    • 对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐。

    • 对于数组,比如char a[1024];它的对齐方式和分别写1024个char 是一样的。虽然他的占用大小超过了8,但他的对齐值仍然是1。

    对于32位机器来说,机器字长是4;对于128位或更高的机器来说,可能是16,32,64...。

    几个例子

    1. 顺序不同,最后的占用大小不同
    type User struct {
    	a uint8
    	b uint64
    	c uint16
    	d uint32
    }
    
    type User2 struct {
    	a uint8
    	c uint16
    	d uint32
    	b uint64
    }
    
    func main() {
    	fmt.Println(unsafe.Sizeof(User{})) // 24
    	fmt.Println(unsafe.Sizeof(User2{})) // 16
    }
    
    1. 结构体中包含结构体 的时候的对齐案例
    type User struct {
    	a uint8  //按1对齐 0%1=0 从0开始到1 占1个字节
    	b uint32 //按4对齐 4%4=0 从4开始到8 占4个字节
    	c uint16 //按2对齐 8%2=0 从8开始到10 占2个字节
      //User 按最大的元素大小对齐,即uint32=4
    	//User到10,10不是4的倍数,往后扩充,所以User占12,对齐值是4
    }
    
    type User2 struct {
      a uint8  // 按1对齐 0%1=0 0-1  占1  注意是:[0, 1)下同
      c uint16 // 按2对齐 2%2=0  2-4  占2    [2, 4)
      
    	//User:占12个字节,对齐值为4
    	u User // 按4对齐 4%4=0 4-16  占12
    	
    	d uint32 // 按4对齐 16%4==0  16-20 占4
    	b uint64 // 按8对齐 24%4==0  24-32 占8
      //User2 按最大的元素大小对齐,即uint64=8
    	//User2到32  32是8的倍数,所以User2占32,对齐值是8
    }
    
    func main() {
    	fmt.Println(unsafe.Sizeof(User{}))  // 12
    	fmt.Println(unsafe.Sizeof(User2{})) // 32
    }
    
    1. 结构体中包含数组
    type two struct {
    	s [100]byte // 按byte=1对齐,
    	//two按最大的元素大小 byte=1 对齐,
    	//two到100  100是1的倍数,所以two占100,对齐值是1
    }
    
    type User2 struct {
    	a uint8  // 按1对齐 0%1=0  0-1  占1
    	c uint16 // 按2对齐 2%2=0  2-4  占2
      
    	//two:占100个字节,但是按元素中最大的对齐(按1对齐),
    	s two // 按1对齐 4%1=0   4-104  占100
    
    	d uint32 // 按4对齐 104%4=0  104-108 占4
    	b uint64 // 按8对齐 108不行,往后找 112%4=0  112-120 占8
    	//User2按最大的元素大小 8 对齐,
    	//User2到120  120正好是8的倍数,所以User2占120
    }
    
    func main() {
    	fmt.Println(unsafe.Sizeof(two{}))   // 100
    	fmt.Println(unsafe.Sizeof(User2{})) // 120
    }
    
    1. 结构体包含的结构体中包含数组和其他元素
    type two struct {
    	s [101]byte // 按byte=1对齐,0-101
    	b uint64 // 按8对齐 104%8=0 104-112  占8
    	//two按最大的元素大小 8 对齐,
    	//two到112  112是8的倍数,所以two占112,对齐值为8
    }
    
    type User2 struct {
    	a uint8  // 按1对齐 0%1=0  0-1  占1
    	c uint16 // 按2对齐 2%2=0  2-4  占2
    
    	//two:占112个字节,但是按元素中最大的对齐(按8对齐),
    	s two // 按8对齐 8%8=0   8-120  占112
    
    	d uint32 // 按4对齐 120%4=0  120-124 占4
    	b uint64 // 按8对齐 128%8=0  128-136 占8
    	//User2按最大的元素大小 8 对齐,
    	//User2到136  136正好是8的倍数,所以User2占136
    }
    
    func main() {
    	fmt.Println(unsafe.Sizeof(two{}))  // 112
    	fmt.Println(unsafe.Sizeof(User2{}))// 136
    }
    

    推荐阅读

    © 2017-2020 版权属于 QXQZX &
  • 相关阅读:
    哈尔滨工业大学计算机学院-模式识别-课程总结(前言)
    吴恩达深度学习笔记(deeplearning.ai)之循环神经网络(RNN)(三)
    吴恩达深度学习笔记(deeplearning.ai)之循环神经网络(RNN)(二)
    吴恩达深度学习笔记(deeplearning.ai)之循环神经网络(RNN)(一)
    卷积神经网络(CNN)之一维卷积、二维卷积、三维卷积详解
    吴恩达深度学习笔记(deeplearning.ai)之卷积神经网络(CNN)(下)
    MATLAB常用字符串函数之二
    matlab常用的字符串操作函数之一
    解决ppt中视频不能播放的问题
    GHOST急速安装win10或win7
  • 原文地址:https://www.cnblogs.com/iQXQZX/p/14049734.html
Copyright © 2011-2022 走看看