天地维杰网

人如秋鸿来有信,事若春梦了无痕


  • 首页

  • Redis

  • java

  • linux

  • 日常问题

  • Spring和Springboot

  • Mac相关

  • 中间件

  • 架构

  • python

  • 前端

  • jvm

  • c语言

  • web3

  • 归档

  • 关于

  • 搜索
close

redis sds 对齐理解

时间: 2022-11-04   |   分类: redis     |   原创   |   阅读: 945 字 ~2分钟

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

以以下结构进行举例:

#include <stdio.h>

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));
}

内存存放数据是为了给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[];
};

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

Datetype LP64 ILP64 LLP64 ILP32 LP32
char 8 8 8 8 8
short 16 16 16 16 16
int 32 64 32 32 16
long 64 64 32 32 32
long long 64 64 64 64 64
pointer 64 64 64 32 32

参考:

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# #内存# #linux# #cpu# #c# #对齐#
分布式AKF拆分原则
Redis sentinel功能
  • 文章目录
  • 站点概览
不与天斗Domino

不与天斗Domino

Programmer & Architect

183 日志
15 分类
224 标签
© 2013 - 2023 天地维杰网 京ICP备13019191号-1
Powered by - Hugo v0.63.2
Theme by - NexT
0%