redis学习 -- 简单动态字符串
Redis沒有使用C語言字符串的形式,通過’\0’作為結尾,而是使用了簡單動態字符串(simple dynamic string)。
當Redis使用的字符串不需要修改字符串的內容的時候,可以使用C語言提供的字符串,當需要修改內容的時候就使用的是簡單動態字符串。Redis鍵值對的操作中,都是使用的簡單動態字符串的方式。
這里可以把簡單動態字符串理解成一個對象,這個對象的底層保存著一個字符串。
SDS定義
在sds.h/sdshdr結構體中定義了SDS的值
struct sdshdr {int len;int free;char buf[];
};
如果我們使用SDS定義一個SDS內容為“Redis”的對象,則組織結構如下圖所示
- free屬性值為0,表示這個SDS沒有分配任何沒有使用的空間。
- len屬性的值是5,表示這個SDS保存了一個五字節長的字符串。
- buf屬性是一個char類型的數組,數組里面保存了字符串的值,并且以’\0’結束。
SDS和C字符串的區別和優勢
常數時間復雜度獲取字符串長度
C字符串獲取字符串長度需要遍歷,耗時。
SDS記錄了長度,可以在O(1)的時間復雜度獲取字符串長度。
杜絕緩沖區溢出
在C語言中使用strcat(dest, src)的時候,用戶自身需要保證dest的空間要大于拼接之后的內存空間。但是很多時候由于疏忽導致內存溢出。SDS解決了這個問題,使用SDS的APIsdscat的時候,他會進行檢測空間大小是否能夠滿足拼接之后的字符串大小。如果不能,他會重新開辟一個拼接后的大度的二倍的字符串空間。
減少修改字符串時帶來的內存重分配次數
C語言中,使用strcat的時候,用戶需要手動開辟空間,然后使用函數進行字符串的拼接。頻繁的申請空間是一個耗時的操作。但是Redis是一個數據庫,很可能會有頻繁的改變數據的操作,所以Redis不能容忍這種問題的出現,于是SDS的結構體中,喲一個free的屬性,這個是用來記錄未使用的空間的,實現了空間的預分配和惰性空間釋放兩種優化策略。
-
空間預分配
當使用SDS的一個API的時候,程序不僅會開辟足夠容納數據的空間,還會額外的開辟未使用的空間。
額外的未使用的空間的開辟,由如下的方式進行決定:
如果程序需要使用的SDS的len長度小于1M的話,程序會開辟和len長度一樣大小的free空間。
如果修改之后的len長度大于1M的話,程序會分配free為1M的空間。
另外上面的兩種方式還會多分配一個自己的空間,用于存放’\0’。
補充一點:只要當需要擴充內存空間的時候,才需要開辟。 -
惰性空間釋放
當SDS需要使用API去釋放空間的時候,這個時候原有字符串會修改,但是開辟的空間并沒有釋放掉,而是將字符串向前移動,用free記錄未使用的空間大小。
二進制安全
SDS底層通過二進制的方式來保存數據。
Redis不僅可以保存文本數據,還可以保存二進制數據。
即使是文本數據,也是轉化成二進制數據保存的。
兼容部分C字符串函數
雖然是通過二進制保存數據,但是為了能夠兼容string的使用,保存了字符串的一些特性。
SDS API
SDS主要的API如下表
| 函數 | 作用 | 時間復雜度 |
|---|---|---|
| sdsnew | 創建一個包含C字符串的SDS | O(N),N為給定的字符串的長度 |
| sdsempty | 創建一個不包含任何內容的空SDS | O(1) |
| sdsfree | 釋放給定的SDS | O(N),N為被釋放的SDS的長度 |
| sdslen | 返回SDS的已經使用空間字節數 | O(1),通過讀取對象的len值直接獲取 |
| sdsavail | 返回SDS未使用的空間字節數 | O(1),通過讀取對象的free的值獲取 |
| sdsdup | 創建一個SDS的副本 | O,N是給定的SDS的長度 |
| stdclear | 清空SDS保存的字符串內容 | O(1),由于惰性空間釋放,只改變了對象的len值 |
| stscat | 將給定C字符串拼接都SDS字符串的末尾 | O(N),N為被拼接的字符串的長度 |
| sdscatsds | 將給定的SDS拼接到另一個SDS字符串的末尾 | O,N為被拼接的SDS字符串的長度 |
| sdscpy | 將給定的C字符串復制到SDS里面,覆蓋原有的字符串 | O(N),N為被復制的C字符串的長度 |
| sdsgrowzero | 用空字符串將SDS擴展到給定長度 | O(N),N為擴展新增的字節數 |
| sdssrange | 保留SDS給定區間的數據,不再全進的數據會被覆蓋或者是清除 | O(N),N為被保留數據的字節數 |
| sdstrin | 接受一個SDS和一個C字符串作為參數,從SDS左右兩端移除所有在C字符串中出現過的字符串 | O(M*N),M為SDS的長度,N為給定C字符串的長度 |
| sdscmp | 對比兩個SDS字符串是否相同 | O(N),N為兩個SDS中較短的那個SDS的長度 |
總結
以上是生活随笔為你收集整理的redis学习 -- 简单动态字符串的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《春雪》第十九句是什么
- 下一篇: opencv 1 图像载入、显示和输出