TCMalloc給每個線程配置設定了一個線程局部緩存,小對象的配置設定是直接由線程局部緩存來完成的,這樣就避免了多線程程式中的鎖競争情況。當線程局部緩存中的記憶體不夠時,會将對象從中央資料結構移動到線程局部緩存中,同時定期的用垃圾收集器把記憶體從線程局部緩存遷移回中央資料結構中。
TCMalloc将尺寸小于等于256 * 1024位元組的對象(“小”對象)和大對象區分開來。大對象直接使用頁級配置設定器從中央頁堆直接配置設定。即,一個大對象總是頁對齊的并占據了整數個數的頁。
1.小對象的配置設定
每個小對象的大小都會被映射到與之接近的可配置設定的class中的一個。例如,所有大小在833到1024位元組之間的小對象時,都會歸整到1024位元組。60個可配置設定的尺寸類别這樣隔開:較小的尺寸相差8位元組,較大的尺寸相差16位元組,再大一點的尺寸差32位元組,如此等等。最大的間隔是控制的,這樣剛超過上一個級别被配置設定到下一個級别就不會有太多的記憶體被浪費。
一個線程緩存包含了由各個尺寸記憶體的對象組成的單連結清單,如圖所示:

當配置設定一個小對象時:(1)我們将其大小映射到對應的尺寸中。(2)查找目前線程的線程緩存中相應的尺寸的記憶體連結清單。(3)如果目前尺寸記憶體連結清單非空,那麼從連結清單中移除的第一個對象并傳回它。當我們按照這種方式配置設定時,TCMalloc不需要任何鎖。這就可以極大提高配置設定的速度,因為鎖/解鎖操作在一個2.8GHzXeon上大約需要100納秒的時間。
如果目前尺寸記憶體連結清單為空:(1)從Central Cache中取得一系列這種尺寸的對象(CentralCache是被所有線程共享的)。(2)将他們放入該線程線程的緩沖區。(3)傳回一個新擷取的對象給應用程式。
如果CentralCache也為空:(1)我們從中央頁堆中配置設定一系列頁面。(2) 将他們分割成該尺寸的一系列對象。(3)将新配置設定的對象放入CentralCache的連結清單上 (4) 像前面一樣,将部分對象移入線程局部的連結清單中。
如果中央頁堆也為空,那麼就從系統中配置設定一系列的頁面(使用sbrk、mmap或者通過在/dev/mem中進行映射),把頁面給中央頁堆,然後繼續上面的操作
2.大對象的配置設定
一個大對象的尺寸會被中央頁堆直接處理,被圓整到一個頁面尺寸(4K)。中央頁堆是由空閑記憶體清單組成的數組。對于
i < 256
而言,數組的第
k
個元素是一個由每個單元是由k個頁面組成的空閑記憶體連結清單。第
256
個條目則是一個包含了長度
>= 256
個頁面的空閑記憶體連結清單:
k個頁面的一次配置設定通過在第
k
個空閑記憶體連結清單中查找來完成。如果該空閑記憶體連結清單為空,那麼我們則在下一個空閑記憶體連結清單中查找,如此繼續。最終,如果必要的話,我們将在最後空閑記憶體連結清單中查找。如果這個動作也失敗了,我們将向系統擷取記憶體(使用
sbrk
、
mmap
或者通過在
/dev/mem
中進行映射)
如果
k
個頁面的配置設定是由連續的> k個頁面的空閑記憶體連結清單完成的,剩下的連續頁面将被重新插回到與之頁面大小接近的空閑記憶體連結清單中去。