首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Redis 源碼閱讀:SDS 動態字符串結構設計解析

     編輯:關於C語言

概述

Redis 未直接使用 C 語言原生字符串(以 \0 結尾的 char*),而是構建了 **SDS(Simple Dynamic Strings)** 作為底層字符串表示。SDS 定義在 sds.h/sds.c 中,提供 O(1) 獲取長度、二進制安全、預分配空間減少內存重分配等特性,是 Redis 高性能的關鍵基礎設施之一。

核心結構 sdshdr

struct sdshdr {
    long len;   // 已使用字節數(不含結尾 \0)
    long free;  // 剩餘可用字節數
    char buf[]; // 柔性數組,存儲實際字符數據,末尾補 \0
};

關鍵設計:

  • len 與 free 分離,避免每次 strlen 掃描,實現 O(1) sdslen()。
  • buf 使用 C99 柔性數組,結構體與數據連續分配,提高緩存局部性。
  • 數據末尾強制補 \0,兼容部分 C 庫函數(如 printf("%s")),但不依賴 \0 判斷長度,故可存儲二進制數據(含嵌入 \0)。

類型別名 sds

typedef char *sds;

sds 實際指向 buf 數組起始位置,而非 sdshdr 結構體開頭。這是一個「指針偏移」技巧:

  • 用戶只見 char*,使用極其簡便。
  • 內部通過指針算術回溯到 sdshdr:sh = (void*)(s - sizeof(struct sdshdr))。

創建 SDS:sdsnewlen

sds sdsnewlen(const void *init, size_t initlen) {
    struct sdshdr *sh = zmalloc(sizeof(struct sdshdr) + initlen + 1);
    if (!sh) return NULL; // 或 SDS_ABORT_ON_OOM
    sh->len = initlen;
    sh->free = 0;
    if (initlen) {
        if (init) memcpy(sh->buf, init, initlen);
        else memset(sh->buf, 0, initlen);
    }
    sh->buf[initlen] = '\0';
    return (char*)sh->buf; // 返回 buf 指針
}

分配一次性完成 header + data + \0,無額外碎片。

長度獲取:sdslen 與指針回溯技巧

size_t sdslen(const sds s) {
    struct sdshdr *sh = (void*)(s - sizeof(struct sdshdr));
    return sh->len;
}

同理,sdsavail 獲取 free,sdsIncrLen 修改長度等均通過此偏移訪問元數據。

優勢總結

特性C 字符串SDS
獲取長度O(N)O(1)
二進制安全否(\0 截斷)是
內存重分配每次增長皆重分配預分配 free 空間,惰性釋放
API 兼容原生需專用 API,但可傳入 C 函數

源碼閱讀建議

  1. 從 sds.h 理解結構體與 sds 別名定義。
  2. 重點研讀 sdsnewlen、sdsMakeRoomFor(空間預分配策略)、sdscat(拼接)、sdsfree(釋放時回溯 header)。
  3. 注意 zmalloc/zfree 封裝的內存統計功能。

結語

SDS 以「結構體頭部 + 柔性數組 + 指針偏移」的經典 C 語言技巧,在保持 char* 使用便利性的同時,賦予了字符串豐富的元數據與高效操作能力,是 Redis 源碼中值得深入學習的經典數據結構實現。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved