Redis字符串簡介
在Redis中,字符串的存儲(chǔ)不是使用C語言傳統(tǒng)的字符串表示柄慰,而是使用一種名為簡單動(dòng)態(tài)字符串(simple dynamic string)的數(shù)據(jù)結(jié)構(gòu)表示踢械。
例如: 這一條指令
redis>SET msg "hello"
OK
鍵值對的鍵是一個(gè)字符串對象奸晴,底層實(shí)現(xiàn)是一個(gè)保存著“msg”的SDS
鍵值對的值是一個(gè)字符串對象贱枣,底層實(shí)現(xiàn)是一個(gè)保存著“hello”的SDS
SDS的數(shù)據(jù)結(jié)構(gòu)
SDS與C字符串區(qū)別
- 字符串的結(jié)尾依然以空字符結(jié)尾监署,遵循了C字符串定義的慣例,為的是可以復(fù)用一部分C中函數(shù)庫的函數(shù)纽哥,即兼容部分C字符串函數(shù)钠乏,而不需要重新寫一套。
- len的定義可以以O(shè)(1)的時(shí)間復(fù)雜度獲取字符串的長度,在傳統(tǒng)C的字符串中春塌,需要進(jìn)行全部遍歷才能獲取長度晓避。在大量使用STRLEN時(shí)SDS將大大提升效率。
-
free的定義可以杜絕緩沖區(qū)溢出只壳,例如:
原來內(nèi)存中緊貼的兩個(gè)字符串俏拱,使用了這個(gè)命令。
strcat(s1,"Cluster");
這樣就會(huì)導(dǎo)致s1的內(nèi)容溢出到了s2中吕世。而在SDS中則不會(huì)發(fā)生彰触,因?yàn)槊看芜M(jìn)行類似這種增加字符的操作,首先會(huì)判斷free的長度是否大于增加的字符命辖,如果小于况毅,則會(huì)重新開辟新的空間再進(jìn)行增加。
那開辟新的空間的長度與增加后的字符串長度相等的嗎尔艇?
不是尔许!為了減少修改字符串時(shí)帶來的內(nèi)存重分配,在SDS修改之后的長度(len長度)小于1MB時(shí)终娃,程序會(huì)多分配與len長度相同的空間味廊,即free的值與len值相等。反之棠耕,則多分配1MB的長度余佛。例如修改之后len的值為13字節(jié),那么程序會(huì)再分配13字節(jié)的未使用空間窍荧,總長度buf數(shù)組則為13+13+1=27字節(jié)(額外的一字節(jié)用來保存空字符)辉巡。若修改之后len的值為30MB,則buf數(shù)組為30MB+1MB+1Byte
- 為了減少內(nèi)存重分配的次數(shù)蕊退,SDS采用的是惰性空間釋放郊楣,當(dāng)字符串縮短時(shí),程序不是立即回收縮短后多出來的字節(jié)瓤荔,而是使用free變量來記錄多出來的字節(jié)净蚤。如果擔(dān)心內(nèi)存浪費(fèi),SDS也提供了API可以在真正有需要時(shí)釋放SDS的未使用空間输硝。
二進(jìn)制安全
Redis作為數(shù)據(jù)庫存儲(chǔ)今瀑,需要滿足各種各樣的存儲(chǔ)形式,若使用傳統(tǒng)C字符串点把,遇到空字符便會(huì)結(jié)束橘荠,而SDS使用len的值來判斷字符串是否結(jié)束,所以程序在寫入數(shù)據(jù)時(shí)怎么樣愉粤,取出也是怎么樣砾医。
假如這種存儲(chǔ)形式以空字符來劃分字符,如用C字符串衣厘,讀了Redis后面的字符就讀不到了如蚜。