天天看點

2012年tcmalloc學習筆記之三一、幾個基本概念二、如何進行優化,提高性能三、把tcmalloc動态庫加到指定目錄四、Mysql如何加入tcmalloc動态庫五、小對象六、配置設定小對象的算法七、大對象八、大對象與小對象的聯系與差別九、跨度十、如何擷取某個頁面究竟屬于哪個跨度十一、如何實作中央陣列十二、一個32為位址空間包含了220個4K頁面,如何了解十三、如何釋放記憶體

2012年tcmalloc學習筆記之三

A.組織結構

1.線程局部緩存ThreadCache

2.中央資料結構CentralHeap

1.大對象

2.小對象

C.測試

1.堆檢查器

2.堆測量器

跨度

中央陣列

修改編譯參數

./configure--disable-cpu-profiler --disable-heap-profiler --disable-heap-checker--enable-minimal

–disable-dependency-tracking –disable-debugalloc

目的隻生成最小的tcmalloc_minimal

修改mysql服務的啟動腳本mysqld_safe,在“#executing

mysqld_safe”行後添加行:

exportLD_PRELOAD="/usr/local/lib/libtcmalloc.so"

目的是在啟動mysql前,加載tcmalloc動态庫。

将尺寸小于<=32K的對象,稱之為“小對象”。

有劃分為170個可配置設定的尺寸類别。

尺寸類别間隔:

較小的尺寸相差8位元組;

較大的尺寸相差16位元組;

再大一點的尺寸差32位元組,如此類推。

最大的間隔(對于尺寸>=~2K的)是256位元組。

一個線程緩存對每個尺寸類都包含了一個自由對象的單向連結清單。

2012年tcmalloc學習筆記之三一、幾個基本概念二、如何進行優化,提高性能三、把tcmalloc動态庫加到指定目錄四、Mysql如何加入tcmalloc動态庫五、小對象六、配置設定小對象的算法七、大對象八、大對象與小對象的聯系與差別九、跨度十、如何擷取某個頁面究竟屬于哪個跨度十一、如何實作中央陣列十二、一個32為位址空間包含了220個4K頁面,如何了解十三、如何釋放記憶體

當配置設定一個小對象時:

目的:我們将其大小映射到對應的尺寸類中。

第一步:查找目前線程的線程緩存中相應的自由清單。

第二步:

1.首先移走自由清單裡的第一個對象;

2.再傳回該對象;

當按照這個算法的時候,TCMalloc不會擷取任何鎖。這就可以極大提高配置設定的速度,因為鎖/解鎖操作在一個2.8GHzXeon上大約需要100納秒的時間。

首先,從該尺寸類别的中央自由清單(中央自由清單是被所有線程共享的)取得一連串對象。

再将他們放入線程局部的自由清單。

将新擷取的對象中的一個傳回給應用程式。

大對象直接使用頁級配置設定器(一個頁是一個4K的對齊記憶體區域)從中央堆直接配置設定。

由此可以看出,一個大對象總是頁對齊的并占據了整數個數的頁。

結論:

1.從中央堆裡直接配置設定;

2.使用的技術手段頁級配置設定器;

3.一個大對象總是頁對齊的;

4.一個大對象總是占據了整數個數的頁;

5.頁是一個4K大小的對齊記憶體區域;

聯系:連續的一些頁面可以被分割為一系列小對象。

差別:但是他們的大小都相同。例如,一個連續的頁面(4K)可以被劃分為32個128位元組的對象。

連續的頁面由一個“跨度”(<code>Span</code>)對象來表示。

或者說跨度用來表示連續的頁面。

一個跨度可以是已被配置設定或者是自由的。

如果是自由的,跨度則會是一個頁面堆連結清單中的一個條目。

如果已被配置設定,它會是一個已經被傳遞給應用程式的大對象,或者是一個已經被分割成一系列小對象的一個頁面。如果是被分割成小對象的,對象的尺寸類别會被記錄在跨度中。

頁面号索引的中央陣列可以用于找到某個頁面所屬的跨度。

也就是說,頁面号有索引,索引儲存在中央陣列,通過中央數組,可以找到頁面的所屬的跨度。

在一個32位的位址空間中,中央陣列由一個2層的基數樹來表示,其中根包含了32個條目,每個葉包含了215個條目(一個32為位址空間包含了220個4K頁面,是以這裡樹的第一層則是用25整除220個頁面)。這就導緻了中央陣列的初始記憶體使用需要128KB空間(215*4位元組),看上去還是可以接受的。

在64位機器上,我們将使用一個3層的基數樹。

頁面的大小:4K= 4 * 210

= 212

一個32為位址空間尋址空間是:232

一個32為位址空間包含了232/ (4 * 210)

= 220個

4K頁面

當一個對象被解除配置設定時,我們先計算他的頁面号并在中央陣列中查找對應的跨度對象。該跨度會告訴我們該對象是大是小,如果它是小對象的話尺寸類别是什麼。如果是小對象的話,我們将其插入到目前線程的線程緩存中對應的自由清單中。如果線程緩存現在超過了某個預定的大小(預設為2MB),我們便運作垃圾收集器将未使用的對象從線程緩存中移入中央自由清單。

如果該對象是大對象的話,跨度會告訴我們該對象覆寫的頁面的範圍。假設該範圍是<code>[p,q]</code>。我們還會查找頁面<code>p-1</code>和頁面<code>q+1</code>對應的跨度。如果這兩個相鄰的跨度中有任何一個是自由的,我們将他們和<code>[p,q]</code>的跨度接合起來。最後跨度會被插入到頁面堆中合适的自由清單中。

當一個對象被釋放的時候,

1.先計算出他的頁面号;

2.然後去中央陣列中查找對應的跨度對象。該跨度會告訴我們對象是大對象,還是小對象;

3.如果是小對象,尺寸類别是什麼;

4.我們将該類别,插入到目前線程的線程緩存中對應的自由清單中;

5.插入之後,如果線程緩存超過了某個預定的大小(預設為2MB),我們便運作垃圾收集器将未使用的對象從線程緩存中移入中央自由清單。

繼續閱讀