Redis源码阅读笔记 ----数据结构部分 sds

本文深入探讨了Redis中使用的Simple Dynamic String (SDS)的数据结构及其优化策略,包括空间预分配和惰性空间释放,旨在减少内存重新分配的频率,提高性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

壹、sds

(SDS)Simple Dynamic String, 从字面意思上来简单理解就是简单的动态字符,其为具有动态增加空间的能力,扩容不需要使用者担心。
好的咱们来看一下他的数据结构吧
这个版本是黄所注释的3.0版本

typedef char *sds;      //注意,sds其实不是一个结构体类型,而是被typedef的char*,好处见下文

struct sdshdr {
    unsigned int len;   //记录buf中已经使用的长度  等于SDS所保存的字符串的长度
    
	unsigned int free;  //buf中未使用的长度
    
	char buf[];         //柔性数组buf
};

sds遵循c字符串以空字符结尾的惯例,但是保存空字符的一字节空间不计算在sds的len属性之中,并且为空字符分配额外的一字节空间,使用这一惯例的好处是可直接重用c字符串函数库里面的额函数,这也符合软件工程的思想。

此处应有图(没图你说个毛)

但是在Redis 3.2 版本中,对数据结构做出了修改,针对不同的长度范围定义了不同的结构,如下,这是目前的结构:

typedef char *sds;      

struct __attribute__ ((__packed__)) sdshdr5 {     // 对应的字符串长度小于 1<<5
    unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {     // 对应的字符串长度小于 1<<8
    uint8_t len; /* used */                       //目前字符串的长度
    uint8_t alloc;                                //已经分配的总长度
    unsigned char flags;                          //flag用3bit来标明类型,类型后续解释,其余5bit目前没有使用
    char buf[];                                   //柔性数组,以'\0'结尾
};
struct __attribute__ ((__packed__)) sdshdr16 {    // 对应的字符串长度小于 1<<16
    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 {    // 对应的字符串长度小于 1<<32
    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 {    // 对应的字符串长度小于 1<<64
    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[];
};

新版带来的好处就是针对长度不同的字符串做了优化,选取不同的数据类型uint8_t或者uint16_t或者uint32_t等来表示长度、一共申请字节的大小等。上面结构体中的 attribute ((packed)) 设置是告诉编译器取消字节对齐,则结构体的大小就是按照结构体成员实际大小相加得到的。(这也是我第一次了解到的) 记得小组每年的纳新面试题,结构体的大小是必考的,试想当年如果能答出来这个的话,会不会刮目呢。


贰、SDS的优劣

typedef char *sds;

e.m.

typedef char *sds; 
sds string = sdsnew ("hello world!");  // 生成这样的一个sds。

我们通过sdsnew返回的实际上是一个char * 类型的指针,这个指针指向的是字符串的开始位置,它的头部信息是在字符串前面分配的,这样带来的好处有:

  • sds可以传给任何 char * 为参数的函数,复用c 函数。
  • string[0], 可以直接访问单个字符,对长度进行检测,杜绝缓冲区溢出。
  • 分配的空间地址是连续的(存疑),对高速缓存的命中率更加友好,
  • 二进制安全,读完的标志为len - free, 可存二进制数据。
  • 获取长度的复杂度为O(1),
    除此之外需要重点介绍的就是关于sds的内存分配策略(主要指修改时),
    redis 作为数据库,经常被用于速度要求严苛,数据被频繁修改的场合,如果每次修改字符串的时候都去执行一次内存重新分配,那么光是执行内存重新分配都会占去很大一部分时间,频繁发生的话,会对性能造成影响。

为了避免之中缺陷,sds解除了字符串长度与底层数组的关联: 在SDS中,buf的长度不一定是字符数量加1,数组里边可以包含未使用的字节,由SDS中的free来记录。

通过未使用空间,SDS使用了空间预分配和惰性空间释放的两种优化策略。

1.空间预分配

空间预分配用于优化SDS的字符串增长操作:即不仅分配修改所需空间,还会额外分配未使用空间。
其中未使用的空间的数量由一下公式决定

  • 进行修改之后,sds的长度(len的属性值)将小于1MB,那么程序分配和len属性同样大小的未使用空间,举个例子,修改之后len将变为12,则程序会另外分配13个未使用的字节,总长为 len = 12+12+1 = 25
    (不要忘记额外的一字节用于保存空字符串)。
  • 如果大于1MB,会分配1MB的未使用空间。举个例子,sds变为12MB,那么程序会分配1MB的未使用空间,则len = 12MB+1MB+1byte。

通过这种预分配策略,SDS连续增长N次字符串所需要的内存冲分配次数从N次将为最对N次。

2.惰性空间释放

用有优化SDS缩短操作:当字符串缩短时,并不立即使用内存重新分配回收多出来的字符,而是使用free把这些字节的长度记录起来等待将来使用。
可能你会担心惰性空间释放策略会导致内存浪费。Never mind,SDS提供相应的api 让我们在有需要的时候,真正的释放SDS的未使用空间。

要说缺点也有:虽然用这么多手段提高效率,但是我们并不知道内部是否重新分配了空间。

可以预见到的是,如果程序中别的地方使用了这个字符串,一经改变之后,没有更新地址,那么原地址就会失效,所以这一定要注意,索性这些问题redis已经帮我们处理就好了,我们只需要拿来用就可以啦!!!
资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在 IT 领域,文档格式转换是常见需求,尤其在处理多种文件类型时。本文将聚焦于利用 Java 技术栈,尤其是 Apache POI 和 iTextPDF 库,实现 doc、xls(涵盖 Excel 2003 及 Excel 2007+)以及 txt、图片等格式文件向 PDF 的转换,并实现在线浏览功能。 先从 Apache POI 说起,它是一个强大的 Java 库,专注于处理 Microsoft Office 格式文件,比如 doc 和 xls。Apache POI 提供了 HSSF 和 XSSF 两个 API,其中 HSSF 用于读写老版本的 BIFF8 格式(Excel 97-2003),XSSF 则针对新的 XML 格式(Excel 2007+)。这两个 API 均具备读取和写入工作表、单元格、公式、样式等功能。读取 Excel 文件时,可通过创建 HSSFWorkbook 或 XSSFWorkbook 对象来打开相应格式的文件,进而遍历工作簿中的每个 Sheet,获取行和列数据。写入 Excel 文件时,创建新的 Workbook 对象,添加 Sheet、Row 和 Cell,即可构建新 Excel 文件。 再看 iTextPDF,它是一个用于生成和修改 PDF 文档的 Java 库,拥有丰富的 API。创建 PDF 文档时,借助 Document 对象,可定义页面尺寸、边距等属性来定制 PDF 外观。添加内容方面,可使用 Paragraph、List、Table 等元素将文本、列表和表格加入 PDF,图片可通过 Image 类加载插入。iTextPDF 支持多种字体和样式,可设置文本颜色、大小、样式等。此外,iTextPDF 的 TextRenderer 类能将 HTML、
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值