2009-10-31 96 views
5

以下是一個非常非常簡單的版本malloc()似乎給我分配了一些空間,但除了沒有free()的事實,我不檢查我是否已超出分配的空間,我如何檢查代碼是否正確?內存分配在C

「C」專家會給我帶來什麼明顯的失誤?

#include <stdio.h> 
#include <unistd.h> 

#define MAX_MEMORY 1024 * 1024 * 2 /* 2MB of memory */ 

void *stack = NULL; /* pointer to available stack */ 
void * memoryAlloc(size) { 
    if (stack == NULL) 
     stack = sbrk(MAX_MEMORY); /* give us system memory */ 

    void *pointer; 
    pointer = (void *)stack + size; /* we always have space :) */ 
    stack += size; /* move in stack forward as space allocated */ 
    return pointer; 
} 
+0

我不會稱之爲內存「堆棧」的舞臺。你當前的實現就像一個堆棧,是的,但是如果你打算像malloc一樣工作,免費,那麼它就是一堆。 – 2009-10-31 18:26:25

+0

非常感謝您的評論! – Radek 2009-10-31 18:29:00

+0

這個分配器是所謂的「池分配器」的開始 - 分配發生像上面那樣,然後當使用池的工作單元完成時,整個塊被立即釋放回系統。它有助於處理由於必須單獨管理每個小配置而導致的泄漏。 Apache使用池 - 一個HTTP請求進入,爲請求設置一個池,當請求完成時池被釋放。對請求沒有任何其他工作需要擔心釋放動態分配的對象。 – 2009-10-31 19:08:09

回答

11

除了基本的問題Ned Batchelder指出,一個更微妙的問題是,一個allocator必須返回已正確的被分配任何對象對齊的地址。在某些平臺(x86)上,除性能問題外,這可能並不重要,但在許多平臺上,這是一個完整的交易斷路器。

我還必須執行(char*)強制執行stack指針算術(您不能對void*類型執行指針算術)。

而且你應該在MAX_MEMORY宏的表達式中放置parens。如果沒有它們,我不認爲你會遇到任何優先級問題,因爲所有高優先級運算符都不是乘法運算,因此無論如何都不是正確的語法。與宏,它是總是比對不起更安全。 (至少有一個例外,其中[]運算符只能綁定到2而不是整個MAX_MEMORY表達式,但即使它在語法上有效,看到MAX_MEMORY[arrayname]也是一種非常奇怪的情況。

事實上,我會把它作爲一個枚舉。

你或許可以保持分配器簡單通過返回的內存塊已正確任何基本數據類型對齊系統(也許一個8字節對齊)上:

/* Note: the following is untested     */ 
/*  it includes changes suggested by Batchelder */ 

#include <stdio.h> 
#include <unistd.h> 

enum { 
    kMaxMemory = 1024 * 1024 * 2, /* 2MB of memory */ 
    kAlignment = 8 
}; 

void *stack = NULL; /* pointer to available stack */ 
void * memoryAlloc(size_t size) { 
    void *pointer; 

    size = (size + kAlignment - 1) & ~(kAlignment - 1); /* round size up so allocations stay aligned */ 

    if (stack == NULL) 
    stack = sbrk(kMaxMemory); /* give us system memory */ 

    pointer = stack; /* we always have space :) */ 
    stack = (char*) stack + size; /* move in stack forward as space allocated */ 
    return pointer; 
} 
+0

測試和工作 – Radek 2009-10-31 19:33:00

6

有幾個問題:

  1. 您在函數中,這是不是在C.

  2. 您可以設置指針stack+size允許申報pointer,但你想它只是stack。否則,您將返回一個指向您分配的內存塊結尾的指針。因此,如果您的調用者在該指針處使用了全部size字節,他將與另一個內存塊重疊。如果在不同的時間獲得不同大小的塊,則會有兩個調用者嘗試使用相同的內存字節。

  3. 當你做stack += size,你是不是size字節,但通過size無效*的,幾乎總是大遞增stack

+3

從C99開始,函數中間的聲明已被允許。 – 2009-10-31 18:23:18

+0

oops:我正在展示我的年齡! – 2009-10-31 18:24:43

+0

所有優點,+1 – 2009-10-31 18:26:41

2

第一,其他都已經注意到,你在塊的中間聲明變量,只允許在C99中使用,但不能在C89/90中使用。即我們必須得出結論,您正在使用C99。其次,你正在用K & R-style(無參數類型)定義你的函數,但同時不在以後聲明參數類型。這樣你就可以依靠C99中不合法的「隱式int」規則。即我們必須得出結論,你使用C99的是而不是。這已經是與「第一」部分的矛盾。 (此外,通常使用無符號的類型來表示「對象大小」的概念。size_t是通常用於此目的的專用類型)。

第三,您在指針上使用指針運算,這在C89/90和C99中都是非法的。我甚至不知道我們可以從中得出什麼結論:)

請確定您嘗試使用哪種語言,我們將從那裏開始。

+0

我錯過了'size'的隱式聲明。 – 2009-10-31 18:37:18

+0

謝謝AndreyT,我打算使用C89,你可以得出結論,我是一個新手,但有很多有用的輸入:)。 – Radek 2009-10-31 21:02:38