• 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

  • 相关阅读:
    【中间件篇-Redis缓存数据库07】Redis缓存使用问题及互联网运用
    IoT物联网速成课程
    Postgresql 阿里云部署排雷
    再来看一个升级的案例
    对实现移动应用界面设计的思考
    AOP是什么?如何使用AOP?
    使用VSCode中遇到的问题及解决办法
    通过java代码实现对json字符串的格式美化(完整版)
    Day9_9 Java学习之Dao层模式与JDBC事务
    gRPC--简单学习笔记
  • 原文地址:https://blog.csdn.net/wejack/article/details/127694676