13.9 Write an aligned malloc and free function that supports allocating memory such that the memory address returned is divisible by a specific power of two.
EXAMPLE
align_malloc (1000,128) will return a memory address that is a multiple of 128 and that points to memory of size 1000 bytes.
aligned_free() will free memory allocated by align_malloc
這道題讓我們寫一對申請和釋放記憶體的函式,而且要求我們申請的記憶體塊的起始地址要能夠被2的倍數整除。題目中給了例子,讓我們申請1000位元組大小的記憶體空間,且起始地址要能被128整除。我們知道,在使用malloc申請記憶體時,我們無法控制堆中具體哪塊記憶體被申請了,如果我們非要首地址被128整除,那麼我們需要些小技巧:我們需要再申請127個位元組大小,這樣我們的首地址即時申請到的不能被128整除,我們也能夠調整到能整除的位置,並且後面的記憶體空間也足夠1000位元組,可以使用如下的程式碼來申請:
void* aligned_malloc(size_t required_bytes, size_t alignment) { int offset = alignment - 1; void *p = (void*)malloc(required_bytes + offset); void *q = (void*)(((size_t)(p1) + offset) & ~(alignment - 1)); return q; }
我們申請了額外的空間alignment-1,然後再調整首地址的位置通過和~(alignment-1)相與,得到能被alignment整除的地址,下面我們就要來看如何釋放記憶體,由於我們多申請了offset的記憶體,我們最終也需要將這些記憶體釋放掉,我們需要一個指標來記錄整個記憶體塊的起始位置,由於新加了指標,別忘了還要給指標申請空間,所以我們需要多申請的空間大小為alignment - 1 + sizeof(void*),參見如下程式碼:
class Solution { public: void* aligned_malloc(size_t required_bytes, size_t alignment) { void *p1; void **p2; int offset = alignment - 1 + sizeof(void*); if ((p1 = (void*)malloc(required_bytes + offset)) == NULL) { return NULL; } p2 = (void**)(((size_t)(p1) + offset) & ~(alignment - 1)); p2[-1] = p1; return p2; } void aligned_free(void *p2) { void *p1 = ((void**)p2)[-1]; free(p1); } };
我們定義一個雙指標p2,在-1的位置存上p1,也就是整個申請的記憶體塊的起始地址,在0的位置存上能被alignment整除的位置,釋放記憶體時從p2中提取出p1,將p1釋放掉即可。