block
為每塊可使用區塊的 metadata ,其中紀錄每個區塊的大小及前一個與後一個區塊的 link。
首先會檢查要配置的記憶體位址是否合法,再去檢查大小是否能至少容納一個區塊所需的 metadata 大小,一個 block 包含 size, *prev, *next
,所以至少要 3 個 word 大小,所以 header_size
為 word_size * 3
,current
去紀錄此可用區塊的位址。
round_up
是為了使宣告的大小能對齊記憶體,因為 x
至少為 1 ,所以當 word_size == 8
時,因為要對齊 8 bytes,所以最右邊 3 bits 要清除為 0 ,所以要 *x + 7
,接著右移 3 bits 後,再左移 3 bits ,就能對齊 8 bytes。但這裡適用於 word_size == 8
時,所以當word_size == 4
,並不適用,所以改成:
則當word_size == 4 or 8
時,都能對齊。
用 pool_malloc
來配置在 memory pool 中的可用區塊,先檢查要配置的記憶體大小是否 > 0,再將要配置的大小對齊 word_size
,最後檢查 pool_free_space
須配置的大小是否足夠,然後用 ret
去紀錄要使用的區塊,由 get_loc_to_place
去尋找可使用的區塊。
因為採用 first-fit ,所以當有足夠大小的區塊時就直接配置,否則就往下尋找。這裡有個問題是 get_loc_to_place
傳入的參數名稱與全域變數 current
是一樣的,會導致自己判斷時可能會錯誤。
因為將 memory pool 的區塊配置,所以更新 free space 的值,先更新 current
的位址,再更新 current->size
的值,為目前 free space 大小 - 以配置的空間大小 - 配置出去的區塊的 metadata 大小(size
)。
最後將 free block 的 prev, next
的 link 接上。
首先求出要釋放的 block 的位址,並將它的大小更新到 free space 中。
用 get_loc_to_free
去找到可以連接的 free block。
再來會檢查 released block 的位址是否跟 free block 相鄰,會有兩種情況,一是 free block 在 released block 前,二是 free block 在 released block 後,再進行合併。
最後合併完的 free block 可能也會跟其他 free block 相鄰,所以需要再次合併,分成兩種情況,分別是存在相鄰的 free block 在前或在後。
AAAA = header_size
BBBB = log2_word_size
CCCC = log2_word_size
DDDD = header_size
EEEE = _size
FFFF = word_size
GGGG = word_size
HHHH = word_size
主要將 node
從 freed list 移出,並用 new
去更新大小跟節點關係,最後更新 rb_tree 的資訊。
這裡主要是做將兩塊 free block 合併,首先將兩塊空間大小加總,再將 freed list 的 link 連接,若是合併後的空間為最後一塊,則會去更新最後一個節點的資訊 g_info.last_node
。
因為考慮到多執行序的問題,所以在配置 block 時,使用 mutex lock,防止可能重複配置空間的問題,首先檢查要配置的大小是否不足 4 bytes,再將 size
加上所需的 metadata 大小,最後去 freed list 尋找合適的空間,若有找到,則回傳位址,若無,則回傳 NULL
。
首先判斷要釋放的指標是否合法,再去判斷是否為 double free ,最後將這塊空間加入到 freed list 中。
IIII = node->size - size
JJJJ = g_info.last_node = first
KKKK = pthread_mutex_lock(&g_info.mutex);
LLLL = pthread_mutex_unlock(&g_info.mutex);