深入理解Redis整數集合(intset)的升級策略:內存優化的核心魔法

引言

作為Redis中最節省內存的數據結構之一,整數集合(intset) 專門用于高效存儲整型數據。但你可能不知道,它背后藏著一個精妙的「動態升級」機制——能在不浪費內存的前提下,靈活適配不同大小的整數。今天我們就來扒開這層神秘面紗,徹底搞懂它的升級策略!


一、先搞清楚:intset到底是啥?

在Redis中,當存儲的整型數據比較「緊湊」(比如都是小整數)時,不會直接用普通的數組或哈希表,而是用更高效的 intset。它的核心設計目標就一個:用最小的內存存最多的整數

1.1 intset的底層數組結構

整數集合的底層結構定義(簡化版)如下:

typedef struct intset {uint32_t encoding;  // 編碼類型,決定元素的實際類型(如 INTSET_ENC_INT16/INT32/INT64)uint32_t length;    // 集合中元素的個數int8_t contents[];  // 存儲元素的數組(實際類型由 encoding 決定)
} intset;

intset 的底層是一個數組(contents[]),但和普通數組不同,它的元素類型不是固定的,而是由一個「編碼標識」(encoding)動態決定的。這個 encoding 有三種可能:

  • INTSET_ENC_INT16:元素是16位有符號整數(范圍:-32768 ~ 32767),每個元素占2字節;
  • INTSET_ENC_INT32:元素是32位有符號整數(范圍:-2^31 ~ 2^31-1),每個元素占4字節;
  • INTSET_ENC_INT64:元素是64位有符號整數(范圍:-2^63 ~ 2^63-1),每個元素占8字節。

舉個栗子:如果一個 intsetencodingINTSET_ENC_INT16,那它的 contents 數組里存的每個數都是16位的,占2字節。

1.2 為什么需要升級?內存優化的核心

假設你有一個 intset,初始存儲的都是1000以內的小整數(完全在int16范圍內),這時候用int16編碼,每個元素只占2字節,內存利用率極高。但如果突然要插入一個40000的數(超過int16的最大值32767),這時候怎么辦?

直接擴容數組?不行! 因為int16的數組每個位置只能存2字節,40000用int16存會溢出(變成負數)。所以必須升級 encoding 到更大的類型(比如int32),讓所有元素都能被正確存儲。

這就是 intset 升級的核心意義:動態調整編碼類型,用最小的內存兼容所有元素


二、升級什么時候觸發?惰性策略的智慧

intset 的升級不是「每次插入都檢查」,而是「按需觸發」——只有當你插入一個「當前編碼存不下」的整數時,才會觸發升級。這種「惰性策略」能避免頻繁的內存分配和數據遷移,提升性能。

觸發條件示例:

  • 當前 encodingINTSET_ENC_INT16(存16位整數),插入一個32768(超過int16最大值32767)→ 觸發升級到 INTSET_ENC_INT32
  • 當前 encodingINTSET_ENC_INT32,插入一個2^32(超過int32最大值2147483647)→ 觸發升級到 INTSET_ENC_INT64
  • 插入的數在當前編碼范圍內(比如int16存20000)→ 不升級,直接插入。

三、升級全過程拆解:從int16到int32的「變身」

升級過程聽起來簡單,但背后涉及內存分配、數據類型轉換、元素遷移等步驟。我們以「int16升級到int32」為例,一步步看:

3.1 步驟1:確定目標編碼類型

首先得判斷新插入的數需要多大的空間。比如插入40000,它超過了int16的范圍(-3276832767),但能被int32容納(-2^312^31-1),所以目標編碼是 INTSET_ENC_INT32

3.2 步驟2:計算新內存大小

原來的 intset 有3個int16元素(每個2字節),總內存是3×2=6字節。現在要插入1個int32元素(4字節),所有元素都要轉為int32(每個占4字節),所以新內存大小是(3+1)×4=16字節。

3.3 步驟3:分配新內存并遷移數據

這一步是關鍵!Redis會做兩件事:

  1. 分配新內存:根據計算出的16字節,申請一塊新的連續內存空間;
  2. 轉換并復制舊數據:把原來的3個int16元素逐個轉為int32(比如10→(int32_t)10,值不變但類型升級),復制到新內存中。

3.4 步驟4:插入新元素并保持有序

intset 中的元素始終是升序排列的(方便二分查找)。所以插入40000時,需要找到正確的位置(這里應該是最后),插入后數組變為 [10, 20, 30, 40000]

3.5 步驟5:更新元數據

最后,把 encoding 改為 INTSET_ENC_INT32length 加1(現在集合有4個元素)。至此,升級完成!


四、升級的三大關鍵特性:為什么這樣設計?

4.1 類型一致性:升級后「一刀切」

升級完成后,集合里所有元素的類型都統一為目標編碼。比如從int16升級到int32后,后續插入的元素如果超過int32范圍,會再次觸發升級到int64。這保證了數據存儲的一致性,避免了混合類型的復雜處理。

4.2 內存優化:用多少,擴多少

升級只在必要時觸發,避免了「為了存大數而預分配大內存」的浪費。比如存1000個int16整數,只需要2000字節;如果提前升級到int32,就需要4000字節——顯然前者更省內存。

4.3 不可降級:升級容易,降級難

一旦升級到更大的編碼(比如int16→int32),即使后續刪除了所有大整數,encoding 也不會降回去。這是Redis的「性能妥協」:頻繁檢查是否可降級會增加開銷,而保留大編碼對后續插入大數更友好(不需要再次升級)。


五、示例演示:直觀感受升級過程

假設我們有一個初始狀態為 INTSET_ENC_INT16intset,存儲 [10, 20, 30](3個元素,內存6字節):

場景1:插入int16范圍內的數(如25)

  • 25在int16范圍內(-32768~32767),無需升級;
  • 直接插入到正確位置(升序),集合變為 [10, 20, 25, 30]length=4,內存占用8字節(4×2)。

場景2:插入int32范圍的數(如40000)

  • 40000超過int16最大值32767,觸發升級到 INTSET_ENC_INT32
  • 新內存大小=(3+1)×4=16字節;
  • 舊數據轉換為int32后復制到新內存,插入40000,集合變為 [10, 20, 30, 40000]
  • encoding 改為 INTSET_ENC_INT32length=4。

總結:intset升級策略的「得與失」

Redis的 intset 升級策略是一個典型的「空間換時間」與「時間換空間」的平衡設計:

  • 優點:通過動態升級,既保證了小整數的內存效率(用int16存小數),又能兼容大整數(升級到int32/int64);
  • 缺點:升級需要重新分配內存并復制數據,時間復雜度是O(N)(N是原元素數量),頻繁插入大數可能影響性能。

理解這一策略后,我們在使用Redis時可以更「聰明」:如果確定要存儲大量小整數(如1~1000),可以用 intset 節省內存;如果需要混合存儲大整數,建議直接用 hashstring 類型,避免頻繁升級帶來的開銷。

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

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

相關文章

高性能計算(HPC)集群和工作流:intel-oneapi-hpc-toolkit安裝與使用

成功安裝了 Intel oneAPI HPC Toolkit!這個工具包包含了很多強大的工具,可以幫助你優化和加速高性能計算(HPC)任務,特別是在使用 Intel 的硬件(如 Xeon 處理器和 GPU)時。 接下來,…

QT vscode cmake 編譯 undefined reference to `vtable for 問題解決

編譯時出現undefined reference to vtable for 問題,是沒有添加頭文件到目標,添加即可: 如果使用的是qt5, 沒有qt_add_executable, 使用qt 5的 自動處理即可: # 啟用 Qt 自動處理功能 set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC …

linux內核奔潰轉儲之kexec、kdump

一、kexec是什么? kexec 是 Linux 內核提供的一種關鍵技術,允許系統?在不經過完整硬件重啟(BIOS/UEFI 初始化)的情況下,直接從當前正在運行的內核加載并啟動另一個新內核?。以下是其核心要點: ?定義與核…

標題:2025金融護網行動實戰指南:從合規防御到智能免疫的體系化進階

引言 2025年,隨著《中國人民銀行業務領域網絡安全事件報告管理辦法》正式實施,金融護網行動已從“合規檢查”升級為“能力對抗”。面對AI驅動的自適應攻擊、勒索病毒與黑灰產協同威脅,金融機構需構建“技術-管理-人才”三位一體的智能防御體…

NEO4j的安裝部署

windows neo4j新版本安裝需要部署jdk17,下面這個版本是jdk8最新的支持版本 neo4j-community-3.5.9-windows.zipIndex of /doc/neo4j/3.5.9/ 啟動 dos面板中啟動 neo4j.bat console linux neo4j新版本安裝需要部署jdk17,下面這個版本是jdk8最新的支…

八股文——JAVA基礎:說一下C++與java的區別

首先,c與java都是面向對象編程,都包含封裝、繼承、多態的特性。但是c多繼承,而java只能單繼承與多實現。 其次,java無法直接訪問內存,java通過引用對向,比如new一個對象,拿到的對象實例實際上是…

Vue3 Composition API 深度解析:告別Options API的局限性

目錄 一、為什么需要Composition API? 二、核心概念:setup() 函數 三、響應式核心:ref() 和 reactive() 1. ref - 處理基本類型/對象 2. reactive - 處理對象 四、生命周期鉤子新寫法 五、強大的邏輯復用:組合式函數 六、響…

IoT/HCIP實驗-5/基于NB-IoT的智慧農業實驗(平臺側開發+端側編碼+基礎調試分析)

文章目錄 概述擴展板 E53_IA1智慧農業平臺測開發功能定義/模型開發編解碼插件開發-消息編解碼插件開發-關聯編解碼插件開發-部署注冊實際設備 智慧農業端側編碼工程配置數據結構定義數據收集任務數據上報任務設備接入過程正確設置接入參數命令響應任務 程序調試其他 概述 本實…

多網絡環境vmware虛擬機配置

環境:一臺臺式機、一臺筆記本、筆記本中安裝虛擬機。臺式機及筆記本都使用wifi連接。 實現效果:虛擬機采用固定ip方式,臺式機可以直接連接虛擬機。 1、VMware環境配置 臺式機ip:192.168.31.43 筆記本ip:192.168.31.…

ZArchiver×亞矩云手機:云端文件管理的“超維解壓”革命

在數字化辦公與移動應用生態中,文件壓縮與解壓是高頻剛需場景,但傳統本地工具受限于設備性能、存儲空間及跨平臺協作痛點。ZArchiver(輕量級壓縮工具)與亞矩云手機的結合,通過“云端算力虛擬化環境”的創新模式&#x…

微幀WZVQA:極致還原人眼感知,精準評估視頻畫質

隨著移動互聯網的不斷發展以及智能手機的普及,短視頻已逐步取代圖片和文字,躋身主流媒體形式的前列。短視頻平臺的興起,讓數十億用戶可以制作,分享并接收彼此的信息,為人們開辟了一條全新的知識獲取途徑。然而&#xf…

信創 CDC 實戰|國產數據庫的數據高速通道:OceanBase 實時入倉 StarRocks

國產數據庫加速進入核心系統,傳統同步工具卻頻頻“掉鏈子”。本系列文章聚焦 OceanBase、GaussDB、TDSQL、達夢等主流信創數據庫,逐一拆解其日志機制與同步難點,結合 TapData 的實踐經驗,系統講解從 CDC 捕獲到實時入倉&#xff0…

Unity 通過AVProMovieCapture插件實現攝像機錄屏

1.AVProMovieCapture插件下載 沒什么好說的,搞到安裝包之后,直接往項目中拉就行。 2.操作面板配置 (1)在Hierarchy創建一個空物體,上面添加Capture From Camera和Camera Selector兩個插件 (2&#xff09…

深度學習:PyTorch卷積神經網絡分享(1)

本文目錄: 一、CNN概述二、CNN日常應用三、CNN的卷積層(一 )基本介紹(二)卷積層計算1.對輸入數據的要求2.卷積核核心參數3.計算過程4.特征圖尺寸計算5.1、多通道卷積計算5.2、多卷積核計算6.PyTorch卷積層API 前言&…

Cesium添加3dtiles并平移到指定經緯度

訪問tileset.json,查看root.transform,12,13,14分別代表模型參考原點的地心坐標Cartesian3(x,y,z) let tileset await Cesium.Cesium3DTileset.fromUrl()構造origin_cartesian3new Cesium.Cartesian3(x,y,z) 設置待平移到的位置經緯高為longitude,latitude,height,例如(116,…

STM32G070x 單片機項目代碼解析:基于 HAL 庫的嵌入式系統開發

項目總體架構 該項目采用標準的 STM32 工程結構,主要包含以下幾個部分: 頭文件包含:系統頭文件和用戶自定義頭文件外設句柄定義:SPI、TIM、UART 等外設的句柄聲明用戶自定義變量:LED 控制、按鍵狀態等標志位初始化函數…

winform mvvm

if (!mvvmContext1.IsDesignMode) InitializeBindings(); 這段代碼的意思是:如果當前應用程序不是處于設計模式(即程序正在運行),就調用InitializeBindings方法來初始化視圖與視圖模型之間的綁定。 void Initiali…

防火墻快速管理軟件,66K超小巧

軟件介紹 今天為大家推薦一款輕量級的Windows防火墻管理工具,這款工具能幫助用戶快速開啟或關閉系統防火墻功能,操作比系統原生設置更加便捷高效。 軟件優勢 相比通過系統設置層層點擊的操作方式,這款僅66KB大小的微型工具只需單擊按鈕…

python中的高級變量III

python中的高級變量III 刪除列表元素(list)擴展知識點 name_list ["Mike","John","Alice"] del name_list[1] # 通過del name_list[1]刪除“John” print(name_list) # 輸出 [Mike, Alice]注意:del …

深入理解Redis

深入理解Redis:高性能內存數據庫的核心原理與應用實踐 1. 引言 在現代互聯網應用中,高性能、低延遲的數據訪問是至關重要的。傳統的關系型數據庫(如MySQL)雖然功能強大,但在高并發場景下往往成為性能瓶頸。Redis&…