2015-05-30 31 views
9

的C代碼:的malloc() - 是否使用BRK()或mmap()的

// program break mechanism 
// TLPI exercise 7-1 

#include <stdio.h> 
#include <stdlib.h> 

void program_break_test() { 
    printf("%10p\n", sbrk(0)); 

    char *bl = malloc(1024 * 1024); 
    printf("%x\n", sbrk(0)); 

    free(bl); 
    printf("%x\n", sbrk(0)); 

} 

int main(int argc, char **argv) { 
    program_break_test(); 
    return 0; 
} 

當編譯如下代碼:

printf("%10p\n", sbrk(0)); 

我得到警告提示:

format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int’

問題1:這是爲什麼?


而且在我malloc(1024 * 1024)之後,程序中斷似乎沒有改變。

這裏是輸出:

9b12000 
9b12000 
9b12000 

問題2:該方法是否在堆中分配內存時開始以備將來使用?或者編譯器改變分配的時間點?否則,爲什麼?


[更新]摘要:BRK()或mmap()的

審查TLPI和檢查手冊頁(從TLPI的作者的幫助),現在我明白瞭如何malloc()決定使用brk()後或mmap(),如下:

mallopt()可以設置參數來控制的malloc()行爲,有一個名爲M_MMAP_THRESHOLD參數,一般來說:

  • 如果請求的內存小於它,將使用brk();
  • 如果請求的內存大於或等於它,將使用mmap();

參數的默認值是128kb(我的系統上),但在我的測試程序中,我使用1MB,所以mmap()選擇,當我改變請求的內存爲32KB,只見brk()將被使用。

該書提到TLPI第147頁和第1035頁,但我沒有仔細閱讀該部分。

該參數的詳細信息可在手冊頁mallopt()中找到。

+3

'#include '? – JS1

+0

@ JS1是的,解決了這個問題,你可以給我一個解釋,我是linux編程的新手...... –

+2

你需要'''sbrk()'的原型''在'unistd.h'中。如果沒有原型,編譯器會假定未知函數返回「int」。 – JS1

回答

11

如果我們改變了計劃,看看那裏的malloc「d內存爲:

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

void program_break_test() { 
    printf("%10p\n", sbrk(0)); 

    char *bl = malloc(1024 * 1024); 
    printf("%10p\n", sbrk(0)); 
    printf("malloc'd at: %10p\n", bl); 

    free(bl); 
    printf("%10p\n", sbrk(0)); 

} 

int main(int argc, char **argv) { 
    program_break_test(); 
    return 0; 
} 

這也許更清楚一點的是sbrk不會改變。 malloc給我們的記憶被映射到一個非常不同的位置。

您也可以在Linux上使用strace來查看進行了哪些系統調用,並找出malloc正在使用mmap執行分配。

+0

我發現有一個'THRESHOLD'來控制是否使用'brk()'或'mmap()',我更新了這個問題。 –

2

malloc不限於使用sbrk分配內存。例如,它可能使用mmap來映射一個大的MAP_ANONYMOUS內存塊;通常mmap將遠離數據段分配虛擬地址。

還有其他的可能性。特別是,mmap作爲標準庫的核心部分,本身並不侷限於標準庫函數;它可以使用操作系統特定的接口。

1

格式「%P」需要類型「無效*」的說法,但參數2的類型爲「詮釋」

回答問題1:編譯器告訴你的參數應該是一個void * ,但是您改爲提供int。如果你花五秒鐘閱讀和理解錯誤,這應該是顯而易見的。有沒有你不明白的部分?如果是這樣,請有關更詳細的問題,其迷惑你,而不是「這是爲什麼?」 ......

了類似的警告應當對printf("%x\n", sbrk(0));,如根據the manual%x預計對應的unsigned參數。另外,根據手冊:

如果任何參數不是相應轉換規範的正確類型,則行爲是未定義的。

通常,我們應該努力編寫在任何系統上以相同方式工作的程序。爲了做到這一點,我們需要制定一套規則。因此,提供了一個警告,告訴您您違反了規則並調用了未定義的行爲。儘管你的未定義的行爲,你的代碼可能會工作,因爲你期望它在你的系統上,在這個時間點 ...但是,這不應該依賴,因爲在未來的某個時候你的電腦可能會獲取更新,導致您的代碼以微妙但破壞性的方式破解,或者可能無法在其他計算機上運行......或者可能僅選擇月的時間爲


問題的答案2,3和4:

該方法是否在堆中分配內存時開始以備將來使用?

不要求一個「堆」標準C的規則中存在,所以這是一個「不」 ......至少,直到你告訴我們你正在使用的編譯器/標準庫。

或者編譯器改變分配的時間點?

可能。編譯器可以執行優化,甚至可以消除您的分配,前提是他們可以推斷出這樣做是安全的(例如可觀察行爲未更改)。

否則,爲什麼?

好問題。

爲什麼我們有免費考慮某些事情的規則未定義的行爲並允許它運行,即使在程序員的危險之中?優化。

爲什麼它很重要,你分配的內存是否那張或以其他方式?你爲什麼要關心?只要你的記憶被分配了,對嗎?只要你可以使用它,而且速度相當快。優化。

爲什麼編譯器會執行優化?我會留下那一個讓你回答;)