Redis里面什么是sdshdr,可以詳細介紹一下嗎?

文章目錄

      • 為什么 Redis 不直接使用 C 語言的字符串?
      • sdshdr 的結構
      • sdshdr 的不同類型
      • sdshdr 帶來的優勢總結

我們來詳細解析一下 Redis 的核心數據結構之一: sdshdr

sdshdr 是 “Simple Dynamic String header” 的縮寫,意為“簡單動態字符串頭”。它是在 Redis 自己實現的字符串庫(SDS)中,用于定義字符串對象的頭部結構。理解了 sdshdr,就能明白為什么 Redis 的字符串操作如此高效和安全。

簡單來說,sdshdr 是 Redis 字符串(SDS)的元數據部分,它緊鄰實際的字符串數據存放在同一塊連續的內存中,記錄了字符串的長度、空余空間等信息。

為什么 Redis 不直接使用 C 語言的字符串?

要理解 sdshdr 的重要性,首先要明白傳統 C 語言字符串(以 \0 結尾的字符數組)的缺陷:

  1. 獲取長度效率低: C 語言字符串本身不記錄長度,要獲取其長度必須遍歷整個字符串,直到遇到 \0,時間復雜度為 O(N)O(N)O(N)
  2. 容易造成緩沖區溢出(Buffer Overflow): 當使用 strcat 等函數拼接字符串時,如果目標數組空間不足,就會發生緩沖區溢出,這是一種嚴重的安全漏洞。
  3. 二進制不安全: C 語言字符串以 \0 (空字符) 作為結束符,這意味著字符串內容不能包含 \0。因此,無法用它來存儲圖片、音頻等二進制數據。
  4. 內存管理復雜: 每次增長或縮短字符串,都需要手動進行復雜的內存重分配,容易出錯且效率不高。

為了解決這些問題,Redis 設計了 SDS。而 SDS 的核心就是 sdshdr 頭部結構。

sdshdr 的結構

一個完整的 SDS 字符串在內存中由兩部分組成:

  1. 頭部(Header):sdshdr 結構體。
  2. 數據(Data): 緊跟在頭部后面的實際字符串內容。

sdshdr 并不是一個單一的結構,為了節省內存,Redis 根據字符串的實際長度,定義了多種不同的 sdshdr 類型(在 sds.h 源碼中定義)。

在 Redis 5.0 及以后的版本中,sdshdr 的通用結構可以看作是:

struct __attribute__ ((__packed__)) sdshdr<T> {T len;          // 已使用長度 (length of the string)T alloc;        // 總分配長度 (total allocated length, excluding header and null terminator)unsigned char flags;  // 標志位 (flags, indicating the header type)char buf[];       // 柔性數組 (flexible array member), 代表實際的字符串數據
};

關鍵字段解釋:

  • len: 記錄了 buf 中已存儲字符串的實際長度。有了它,Redis 獲取字符串長度的時間復雜度是 O(1)O(1)O(1),極其高效。
  • alloc: 記錄了不包括頭部和末尾 \0 的情況下,總共為 buf 分配的內存空間大小。lenalloc 的差值就是剩余可用空間。
  • flags: 一個3位的字段,用來表示當前 sdshdr 的具體類型。
  • buf[]: 這是一個“柔性數組成員”,是 C99 的一個特性。它表示 buf 指向 sdshdr 結構體之后緊跟的內存地址,這里存放著實際的字符串內容。字符串的末尾同樣會追加一個 \0,以兼容部分 C 語言函數庫。

__attribute__ ((__packed__)) 是一個 GCC 的指令,用于告訴編譯器取消結構體在編譯過程中的內存對齊優化,使得結構體成員緊湊排列,從而節省內存。

sdshdr 的不同類型

根據 flags 字段的值,Redis 會使用不同的 sdshdr 結構,主要區別在于 lenalloc 字段的數據類型,從而節省頭部占用的空間:

flags類型lenalloc 的數據類型頭部大小
0sdshdr5(沒有 len/alloc 字段)1 字節
1sdshdr8uint8_t (8位無符號整數)3 字節
2sdshdr16uint16_t (16位無符號整數)5 字節
3sdshdr32uint32_t (32位無符號整數)9 字節
4sdshdr64uint64_t (64位無符號整數)17 字節

特別說明 sdshdr5:
sdshdr5 是一個特例,它沒有 lenalloc 字段。它的 flags 字段本身就編碼了字符串的長度(高5位存長度,低3位存類型)。它只能用于存儲非常短的字符串。

Redis 會根據字符串的長度自動選擇最小的、能容納該字符串的 sdshdr 類型,實現極致的內存優化。

sdshdr 帶來的優勢總結

基于 sdshdr 結構,Redis 的 SDS 相比 C 語言字符串獲得了巨大優勢:

  1. 常數時間復雜度的長度獲取: 直接讀取 len 屬性即可,時間復雜度為 O(1)O(1)O(1)
  2. 杜絕緩沖區溢出: 當對 SDS 進行修改時(如 APPEND),SDS 的 API 會先檢查 alloc - len 的剩余空間是否足夠。如果不足,它會自動進行內存重分配,擴展 buf 的大小,然后再執行操作,從而保證了安全。(對這里len和alloc不理解的可以看文章末尾!!!)
  3. 空間預分配與惰性釋放(減少內存重分配次數):
    • 空間預分配: 當對 SDS 進行擴展時,如果修改后字符串長度小于 1MB,程序會分配 len * 2 的空間;如果超過 1MB,則會額外多分配 1MB 的空間。這種策略避免了每次增加字符串都重新分配內存,提升了性能。
    • 惰性空間釋放: 當縮短 SDS 字符串時,程序并不會立即釋放多出來的空間,而是更新 len 字段,將這部分空間記錄為未使用,以備將來再次使用。
  4. 二進制安全: SDS 使用 len 屬性來判斷字符串結束,而不是 \0。因此 buf 中可以包含任意字符,包括 \0。這使得 SDS 可以安全地存儲任何二進制數據。
  5. 兼容部分 C 語言函數: SDS 字符串的末尾依然保留了一個 \0 字符(這個 \0 不計入 len 長度),這使得那些只讀取而不修改字符串的 C 語言函數(如 printfstrcmp)可以直接處理 SDS 的 buf 部分。

綜上所述,sdshdr 是 Redis 高性能字符串實現的關鍵基石。它通過一個精巧的頭部設計,解決了傳統 C 語言字符串的諸多痛點,為 Redis 提供了高效、安全且功能豐富的字符串處理能力。

下一篇:
Redis中的sdshdr的len和alloc那塊的知識點詳解

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/91986.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/91986.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/91986.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

RocketMq如何保證消息的順序性

文章目錄1.順序消息的全流程1.1 發送階段&#xff1a;消息分區1.2.存儲階段&#xff1a;順序寫入1.3.消費階段&#xff1a;串行消費2.第三把鎖有什么用?3.順序消費存在的問題和Kafka只支持同一個Partition內消息的順序性一樣&#xff0c;RocketMQ中也提供了基于隊列(分區)的順…

zabbix平臺無法刪除已停用主機的處理案例

在zabbix平臺上刪除已停用的主機&#xff0c;提示“SQL描述式執行已失敗: "DELETE FROM items WHERE (itemid IN &#xff08;.....)”&#xff0c;無法刪除&#xff0c;本文為處理情況。一、問題現象在zabbix平臺上刪除已停用的主機&#xff0c;提示“SQL描述式執行已失敗…

【計算機網絡】6應用層

1.網絡應用模型 特性 客戶/服務器模型(Client-Server, C/S) 對等模型(Peer-to-Peer, P2P) 中心化 是(依賴服務器) 否(去中心化) 角色特點 服務器 客戶機 無中心服務器 提供計算服務 請求計算服務 每個節點(Peer)既是客戶機也是服務器 永久在線 間歇接入網絡 節點間…

基于 Spring Boot + Vue 實現人臉采集功能全流程

一、技術棧與依賴引入 后端依賴 (pom.xml) <!-- 百度AI SDK --> <dependency><groupId>com.baidu.aip</groupId><artifactId>java-sdk</artifactId><version>4.16.19</version><exclusions><exclusion><grou…

《Python基礎》第3期:使用PyCharm編寫Hello World

我們寫文檔大多用 Word、寫表格大多用 Excel、寫幻燈片大多用 PPT。 寫代碼也需要一個軟件作為編輯器&#xff08;傳說的大神用記事本寫代碼純屬玩笑了&#xff0c;越是大神越追求效率&#xff0c;用的軟件功能越強&#xff09;。 Python 現在已經有了非常多的代碼編輯器&#…

我的第一個開源項目:排序算法的多種實現方式

以 排序算法 為例&#xff0c;展示如何在 Python 中進行不同實現方式的對比項目概述本項目旨在通過 Python 實現幾種經典的排序算法&#xff0c;并通過性能對比、代碼注釋和優化手段&#xff0c;為開源社區提供參考。選擇排序、冒泡排序、快速排序和歸并排序作為主要算法&#…

5G-LEO - 用于 5g satellite 鏈接的 OpenAirInterface? 擴展

目標&#xff1a;5G-LEO 旨在加速 OAI 作為開源工具的發展&#xff0c;允許衛星通信社區交流和比較 5G NTN 結果&#xff0c;并促進研發活動的合作。擴展的OAI軟件庫被視為開發早期原型的重要工具&#xff0c;用于驗證關鍵的5G NTN設計方面&#xff0c;并為3GPP標準化過程提供及…

基于 Mybatis 框架*的完整開發流程與順序

基于 MyBatis 框架 的完整開發流程與順序一、環境準備階段1. 新建 Maven 項目&#xff08;或普通 Java 項目&#xff09;作用&#xff1a;用 Maven 統一管理依賴&#xff0c;自動下載 MyBatis、MySQL 驅動等 Jar 包操作&#xff1a;IDE&#xff08;如 IDEA&#xff09;選 Maven…

機械學習--決策樹(實戰案例)

決策樹分兩種分類和回歸&#xff0c;這篇博客我將對兩種方法進行實戰講解一、分類決策樹代碼的核心任務是預測 “電信客戶流失狀態”&#xff0c;這是一個典型的分類任務數據集附在該博客上&#xff0c;可以直接下載代碼整體結構整理代碼主要分為以下幾個部分&#xff1a;導入必…

SQL154 插入記錄(一)

描述牛客后臺會記錄每個用戶的試卷作答記錄到exam_record表&#xff0c;現在有兩個用戶的作答記錄詳情如下&#xff1a;用戶1001在2021年9月1日晚上10點11分12秒開始作答試卷9001&#xff0c;并在50分鐘后提交&#xff0c;得了90分&#xff1b;用戶1002在2021年9月4日上午7點1分…

BeanFactory 和 ApplicationContext 的區別?

口語化答案好的&#xff0c;面試官。BeanFactory和ApplicationContext都是用于管理Bean的容器接口。BeanFactory功能相對簡單。提供了Bean的創建、獲取和管理功能。默認采用延遲初始化&#xff0c;只有在第一次訪問Bean時才會創建該Bean。因為功能較為基礎&#xff0c;BeanFact…

VNC連接VirtualBox中的Ubuntu24.04 desktop圖形化(GUI)界面

測試環境&#xff1a;VirtualBox 7,Ubuntu24.04 desktop,Ubuntu24.04 server(no desktop) 一、下載和安裝dRealVNC viewer。 二、配置 VirtualBox 網絡&#xff1a;NAT 模式 端口轉發 1、打開 VirtualBox&#xff0c;選擇您的 Ubuntu 虛擬機&#xff0c;點擊 設置。 選擇 網…

浮動路由和BFD配置

拓撲圖 前期的拓撲圖沒有交換機配置步驟 1、配置IP地址 終端IP地址的配置 路由器IP地址的配置 配置router的對應接口的IP地址 <Huawei>sys [Huawei]sysname router [router]interface Ethernet 0/0/0 [router-Ethernet0/0/0]ip address 192.168.10.254 24 [router-Ethern…

Docker 實戰 -- Nextcloud

文章目錄前言1. 創建 docker-compose.yml2. 啟動 Nextcloud3. 訪問 Nextcloud4. 配置優化&#xff08;可選&#xff09;使用 PostgreSQL使用 redis添加 Cron 后臺任務5. 常用命令6. 反向代理&#xff08;Nginx/Apache&#xff09;前言 當你迷茫的時候&#xff0c;請點擊 Docke…

【計算機網絡 | 第2篇】計算機網絡概述(下)

文章目錄七.因特網服務提供商&#x1f95d;八.接入網&#x1f95d;主流的家庭寬帶接入方式介入網工作原理&#x1f9d0;DSL技術&#xff1a;銅線上的“三通道”通信DSL的速率標準呈現出顯著的"不對稱"特征&#x1f914;電纜互聯網接入技術&#x1f34b;?&#x1f7e…

SpringMVC 6+源碼分析(四)DispatcherServlet實例化流程 3--(HandlerAdapter初始化)

一、概述 HandlerAdapter 是 Spring MVC 框架中的一個核心組件&#xff0c;它在 DispatcherServlet 和處理程序&#xff08;handler&#xff09;之間扮演適配器的角色。DispatcherServlet 接收到 HTTP 請求后&#xff0c;需要調用對應的 handler 來處理請求&#xff08;如控制器…

【lucene】FastVectorHighlighter案例

下面給出一套可直接拷貝運行的 Lucene 8.5.0 FastVectorHighlighter 完整示例&#xff08;JDK 8&#xff09;&#xff0c;演示從建索引、查詢到高亮的全過程。 > 關鍵點&#xff1a;字段必須 1. 存儲原始內容&#xff08;setStored(true)&#xff09; 2. 開啟 TermVecto…

C++返回值優化(RVO):高效返回對象的藝術

在C開發中&#xff0c;按值返回對象的場景十分常見&#xff08;如運算符重載、工廠函數等&#xff09;&#xff0c;但開發者常因擔憂“構造/析構的性能開銷”而陷入糾結&#xff1a;該不該返回對象&#xff1f;如何避免額外成本&#xff1f;本文將剖析痛點、拆解錯誤思路&#…

用 PyTorch 實現一個簡單的神經網絡:從數據到預測

PyTorch 是目前最流行的深度學習框架之一&#xff0c;以其靈活性和易用性受到開發者的喜愛。本文將帶你從零開始&#xff0c;用 PyTorch 實現一個簡單的神經網絡&#xff0c;用于解決經典的 MNIST 手寫數字分類問題。我們將涵蓋數據準備、模型構建、訓練和預測的完整流程&#…

四級頁表通俗講解與實踐(以 64 位 ARM Cortex-A 為例)

&#x1f4d6; &#x1f3a5; B 站博文精講視頻&#xff1a;點擊鏈接&#xff0c;配合視頻深度學習 四級頁表通俗講解與實踐&#xff08;以 64 位 ARM Cortex-A 為例&#xff09; 本文面向希望徹底理解現代 64 位架構下四級頁表的開發者&#xff0c;結合 ARM Cortex-A 系列處理…