• Redis sds packed对齐理解


    Redis sds 的源码中,使用了 __attribute__ ((__packed__)) ,一般情况下,结构体会按其所有变量大小的最小公倍数做字节对齐,而用packed修饰以后,结构体则变为按1字节进行对齐。这个最小公倍数如何进行理解呢?

    以以下结构进行举例:

    #include 
    
    typedef struct MemAlign  
    {  
        char a[18];  
        double b;     
        char c;  
        int d;    
        short e;      
    }MemAlign;
    
    typedef struct __attribute__ ((__packed__))  MemAlignPacked  
    {  
        char a[18];  
        double b;     
        char c;  
        int d;    
        short e;      
    }MemAlignPacked;  
    
    int main(void){
        struct MemAlign m;
        struct MemAlignPacked mp;
        printf("========>%d", sizeof(m));
        printf("========>%d", sizeof(mp));
    }
    
    • 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

    内存存放数据是为了给CPU进行使用,而CPU访问内存数据时会受到地址总线宽度的限制,并且CPU从内存中获取数据时起始地址必须是地址总线宽度的倍数,也就是说CPU是将内存分为一块一块的,块的大小取决于地址总线宽度,并且CPU读取数据也是一块一块读取的,块的大小称为(memory granularity)内存读取粒度。

    上面的结构中,有char a[18]这个属性,说明这个属性是占个字节的,在32位CPU的内存模型中,以4个字节对齐(如下图1),属性char a[18]因为占了18个字节,会需要补齐2个字节达到4的最小公倍数20,然后接着分配double b的内存地址(如下图2)。而使用了__packed__修饰以后,就不需要补齐。

    而在64位CPU的内存模型中,以8个字节进行对齐(如下图1)。则案例结构如下图2。我的mac是64位的,跑文章开始的代码跑出的结果和猜测的一样。

    所以在redis的sds的源码中,出现的sdshdr5 、sdshdr8、sdshdr16、sdshdr32、sdshdr64,都使用了 __attribute__ ((__packed__))进行紧凑排列。好处在于节省内存和方便buf[-1]取到flags地址,获取类型更加方便。

    /* Note: sdshdr5 is never used, we just access the flags byte directly.
     * However is here to document the layout of type 5 SDS strings. */
    struct __attribute__ ((__packed__)) sdshdr5 {
        unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
        char buf[];
    };
    struct __attribute__ ((__packed__)) sdshdr8 {
        uint8_t len; /* used */
        uint8_t alloc; /* excluding the header and null terminator */
        unsigned char flags; /* 3 lsb of type, 5 unused bits */
        char buf[];
    };
    struct __attribute__ ((__packed__)) sdshdr16 {
        uint16_t len; /* used */
        uint16_t alloc; /* excluding the header and null terminator */
        unsigned char flags; /* 3 lsb of type, 5 unused bits */
        char buf[];
    };
    struct __attribute__ ((__packed__)) sdshdr32 {
        uint32_t len; /* used */
        uint32_t alloc; /* excluding the header and null terminator */
        unsigned char flags; /* 3 lsb of type, 5 unused bits */
        char buf[];
    };
    struct __attribute__ ((__packed__)) sdshdr64 {
        uint64_t len; /* used */
        uint64_t alloc; /* excluding the header and null terminator */
        unsigned char flags; /* 3 lsb of type, 5 unused bits */
        char buf[];
    };
    
    • 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

    一般情况下windows64位一般使用LLP64模型,64位Unix,Linux使用的是LP64模型

    DatetypeLP64ILP64LLP64ILP32LP32
    char88888
    short1616161616
    int3264323216
    long6464323232
    long long6464646464
    pointer6464643232

    参考:

    https://juejin.cn/post/7074538808259117064

    https://blog.csdn.net/wejack/article/details/127686029

    https://blog.csdn.net/weixin_40997360/article/details/79948968

    https://zhuanlan.zhihu.com/p/140063999

    https://juejin.cn/post/6922352059517779976

  • 相关阅读:
    设计模式-享元模式
    SAP 财务月结之 外币评估(TCODE:FAGL_FC_VAL,S4版本用 FAGL_FCV)<转载>
    总监调岗至前台,企业被判赔偿26万,法院:“侮辱性调岗”违法
    HStreamDB Newsletter 2022-07|分区模型优化、数据集成框架进一步完善
    电脑使用技巧分享  电脑小白们快收藏
    自动化测试(五):自动化测试框架的搭建和基于yaml热加载的测试用例的设计
    (学习日记)2022.7.21
    小谈设计模式(23)—桥接模式
    金蝶云星空与聚水潭对接集成物料查询连通商品上传(新)(物料主数据同步策略)
    商业地产数字化转型分析
  • 原文地址:https://blog.csdn.net/wejack/article/details/127694676