[英]Own Malloc implementation freeze at brk
為了練習,我目前正在嘗試在 c 中編寫自己的 malloc function。 所以我的問題是,在從堆中進行一些分配后,我的程序將凍結。 我找到了導致凍結的代碼段,當我調用 brk sys 調用時它會凍結。 我已經嘗試在那里解鎖我的互斥鎖,但這沒有用。 為了測試它,我編寫了一個永久循環並在一個數組中分配 memory 並隨機釋放它。
static list *head = NULL;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
typedef struct list
{
size_t size_;
int free_;
struct list *next_;
struct list *previouse_;
} block;
void blockAdd(block *href, size_t size)
{
href->free_ = FALSE;
href->next_ = NULL;
href->previouse_ = NULL;
if (!head || head > href)
{
if (head)
{
head->previouse_ = href;
}
href->size_ = size + sizeof(block);
href->next_ = head;
head = href;
}
else
{
href->next_ = NULL;
block *current = head;
while (current->next_ && current->next_ < href)
{
current = current->next_;
}
href->size_ = size + sizeof(block);
href->next_ = current->next_;
href->previouse_ = current;
current->next_ = href;
}
}
void *findExactSizeMatch(size_t size)
{
block *href = head;
size_t t = size + sizeof(block);
while (href)
{
if (href->size_ == (size + sizeof(block)) && href->free_)
{
href->free_ = FALSE;
return href;
}
href = href->next_;
}
return NULL;
}
void *findLagerBlock(size_t size)
{
block *href = head;
while (href)
{
if (href->free_ && href->size_ > size)
{
return split(href, size);
}
href = href->next_;
}
return NULL;
}
void *allocateMemory(size_t size)
{
block *new_block = sbrk(BLOCK_SIZE(size));
if (new_block == SBRK_FAILED)
{
exit(1);
}
blockAdd(new_block, size);
return new_block;
}
bool checkAllFree()
{
block *href = head;
while (href)
{
if (!href->free_)
{
return FALSE;
}
href = href->next_;
}
return TRUE;
}
void freeList(block *ptr)
{
if (checkAllFree())
{
if (brk(ptr) == BRK_FAILED)
{
exit(1);
}
head = NULL;
}
}
void merge()
{
block *href = head;
while (href && href->next_)
{
if (href->free_ && href->next_->free_)
{
href->size_ = href->next_->size_;
href->next_ = href->next_->next_;
}
href = href->next_;
}
}
//--------------------------Here it makes some strange things
shrinkHeap()
{
block *href = head;
while (href && href->next_)
{
href = href->next_;
}
if (href && href->free_)
{
if (brk(href) == BRK_FAILED)
{
exit(1);
}
href->previouse_->next_ = href->next_;
}
}
void *malloc(size_t size)
{
if (!size)
{
return NULL;
}
pthread_mutex_lock(&mutex);
block *new_list = NULL;
new_list = findExactSizeMatch(size);
if (new_list)
{
pthread_mutex_unlock(&mutex);
return new_list + sizeof(block);
}
new_list = allocateMemory(size);
pthread_mutex_unlock(&mutex);
return new_list + sizeof(block);
}
void free(void *ptr)
{
if (!ptr || !head)
{
return;
}
pthread_mutex_lock(&mutex);
block *pref = ptr - sizeof(block);
pref->free_ = TRUE;
freeList(pref);
shrinkHeap();
merge();
pthread_mutex_unlock(&mutex);
}
我不知道為什么,但是 brk 凍結了我的程序。
謝謝你的幫助!
您的代碼中有多個問題:
在blockAdd
中,如果href->next_
NULL
else
分支中的 NULL,則您無法更新href->next_->previouse_
。
findLagerSize
應更改為findLargerSize
並應使用size + sizeof(block)
來定位 memory 的適當塊。
allocateMemory
也不正確:傳遞給sbrk
的大小應該包括sizeof(block)
額外字節,因此分配的塊應該插入堆中,如果它大於size + sizeof(block)
則應該拆分。
在freeList
中,如果checkAllFree()
返回 true,您應該調用brk(head)
,而不是brk(ptr)
。
在merge
中,您沒有正確更新href->size
:您應該合並大小。 此外,您不會更新href-_next->previouse_
。
shrinkHeap
的原型應該有一個返回類型和一個參數列表:
void shrinkHeap(void)
在shrinkHeap
,您必須在調用brk
之前更新鏈接,因為調用后指針可能會變得無效。 此外,您必須測試href->previouse_
是否不是NULL
,此更新可以簡化為:
if (href->previouse_;= NULL) href->previouse_->next_ = NULL;
您的malloc
function 有一個缺陷: return new_list + sizeof(block);
不返回指向分配塊的指針,而是返回一個更遠的指針,導致應用程序寫入超出分配塊的末尾,可能會破壞競技場。 此外,free 計算的指針不指向block
,即使程序沒有寫入 memory 塊並調用未定義的行為,也會導致 arena 進一步損壞。
在malloc()
的兩個地方,您應該改為:
return new_list + 1;
同樣在free()
中,但不一定會導致錯誤,您應該避免對void
指針執行算術運算,將它們轉換為unsigned char *
用於可移植代碼:
block *pref = (void *)((unsigned char*)ptr - sizeof(block));
或在正確鍵入后執行算術:
block *pref = ptr; ptr -= 1;
這是修改后的版本:
static struct list *head = NULL;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
typedef struct list {
size_t size_; // block size, including header
int free_; // free indicator, true or false
struct list *next_;
struct list *previouse_;
} block;
void blockAdd(block *href, size_t size) {
href->free_ = FALSE;
href->size_ = size + sizeof(block);
href->next_ = NULL;
href->previouse_ = NULL;
if (!head || head > href) {
if (head) {
head->previouse_ = href;
}
href->next_ = head;
head = href;
} else {
block *current = head;
while (current->next_ && current->next_ < href) {
current = current->next_;
}
href->next_ = current->next_;
if (href->next_) {
href->next_->previouse_ = href;
}
href->previouse_ = current;
current->next_ = href;
}
}
void *findExactSizeMatch(size_t size) {
block *href = head;
size_t t = size + sizeof(block);
while (href) {
if (href->free_ && href->size_ == t) {
href->free_ = FALSE;
return href;
}
href = href->next_;
}
return NULL;
}
void *findLargerBlock(size_t size) {
block *href = head;
size_t t = size + sizeof(block);
while (href) {
if (href->free_ && href->size_ > t) {
return split(href, size);
}
href = href->next_;
}
return NULL;
}
void *allocateMemory(size_t size) {
/* should add size of `block` */
block *new_block = sbrk(BLOCK_SIZE(size));
if (new_block == SBRK_FAILED) {
exit(1);
}
/* should split new_block if BLOCK_SIZE(size) > size */
blockAdd(new_block, size);
return new_block;
}
bool checkAllFree() {
block *href = head;
while (href) {
if (!href->free_) {
return FALSE;
}
href = href->next_;
}
return TRUE;
}
void freeList(block *ptr) {
if (checkAllFree()) {
if (brk(head) == BRK_FAILED) {
exit(1);
}
head = NULL;
}
}
void merge(void) {
block *href = head;
while (href && href->next_) {
if (href->free_ && href->next_->free_) {
href->size_ += href->next_->size_;
href->next_ = href->next_->next_;
href->next_->previouse_ = href;
}
href = href->next_;
}
}
void shrinkHeap(void) {
block *href = head;
if (href) {
while (href->next_) {
href = href->next_;
}
if (href->free_) {
if (href->previouse_ != NULL) {
href->previouse_->next_ = NULL;
}
if (brk(href) == BRK_FAILED) {
exit(1);
}
}
}
}
void *malloc(size_t size) {
if (!size) {
return NULL;
}
pthread_mutex_lock(&mutex);
block *new_list = findExactSizeMatch(size);
if (new_list == NULL) {
new_list = findLargerSize(size);
}
if (new_list == NULL) {
new_list = allocateMemory(size);
}
pthread_mutex_unlock(&mutex);
if (new_list)
return new_list += 1;
else
return NULL;
}
void free(void *ptr) {
if (!ptr || !head) {
return;
}
pthread_mutex_lock(&mutex);
block *pref = ptr;
pref -= 1;
pref->free_ = TRUE;
freeList(pref);
merge();
shrinkHeap();
pthread_mutex_unlock(&mutex);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.