2017-04-11

fbstring與fbvector原始碼心得導讀

代碼已經使用C++11風格,編譯器需支援C++11。

fbstring

做的非常複雜,所有最佳化的方式都用上了,時間空間均壓榨到了極限。

有些函式庫對於記憶體配置使用三個指標,A指向記憶體開頭,B指向字串結尾,C指向記憶體結尾。fbstring採用一個指標 + 兩個size_t。不過大多數的機器size_t佔用空間跟指標一樣大。

根據字串長短分成三種處理模式,短/中/長。以下均假設機器64 bits。

挪用size_t的兩個bit來紀錄狀態,,size_t長度64 bits,挪用了兩個bits,所以理論支援的字串最長可以到2的62次方。也因為挪用了兩個bits,須考慮機器是Big Endian或是Little Endian。代碼中提供kIsLittleEndian定義,可根據自己的機器來改動。

短字串:

利用三個指標佔用的記憶體來存。三指標合計24 bytes,一般的函式庫需要一個byte紀錄長度。字串結尾又需要加\0,所以被吃掉2個bytes,故短字串最長22bytes。結果 fbstring採用絕頂聰明的方式。可以存到23bytes。

假設短字串23bytes存滿,結尾就是'\0',所以是0x00。

挪用兩個bits紀錄,它把短字串訂成00,中字串訂成10,長字串訂成01。短字串結尾是0x00,當然不影響。

正常的情況需要挪用一個bytes紀錄長度,通常放在最後一個byte。fbstring在短字串底下,不紀錄長度,而是紀錄「最大短字串長度-現在長 度」

最大短字串長度當然就是23,如果現在字串長度也是23,那最後一個byte就是0,剛好也是'\0'。

如果字串長度22bytes。倒數第二byte是'\0',最後byte是1,存放1這個bytes,最前2 bits是用來紀錄短中長資訊。短字串本來就是00兩個bits,還是不影響。

中字串:

採用動態配置記憶體。不使用new,而是用函式庫jemalloc,這應該是目前最強的記憶體函式庫。中型字串最大254 bytes。不知道為什麼採用254,一般記憶體配置合適大小256 bytes,預留字串結尾\0,那也應該用255。函式庫卻把中型字串訂成254,原因不明。函式庫有考慮到字元大小未必是一byte。如果單字元超過 1byte,實際上字串會更短。

長字串:

超過254 bytes一律使用長字串,也是採用動態配置記憶體。但有使用Copy on write技術,多字串共用同一筆資料,有修改字串才複製。當然大家都知道多執行序使用Copy on write會出錯,所以操作字串一定要加鎖。當然C++11有導入atomic,直接使用標準函式庫即可。

不論是短中長字串,在配置記憶體的時候,能用jemalloc函式庫就用,如不能用也會視情況採用malloc/calloc/realloc三個標準函 式庫。

如資料量低於50%使用malloc。
如字串40,總空間100,這時候要串接一個200字串。就直接malloc配置新記憶體。舊字串40複製過去,再串接200字串。

如資料量高於50%使用realloc
如字串60,總空間100,這時候使用realloc配置記憶體。希望函式庫可以加大同一塊記憶體。就不用搬移60字串。

fbvector

最小會使用64 bytes,即便是空的vector,還是配置64 bytes。加大vector的策略是用1.5倍,不是2倍。

配置記憶體還是使用jemalloc函式庫。但不採用malloc/calloc/realloc。

會根據資料型態,以及當時狀況,優先使用std::memcpy,再使用std::memmove,都不行才會使用std::copy複製。當然也因為是 C++11,能用move語意就優先使用。

沒有留言: