《Linux/Unix系統程式設計手冊》讀書筆記 目錄

第7章:

記憶體分配

通過增加堆的大小分配記憶體,通過提升program break位置的高度來分配記憶體。

基本學過C語言的都用過malloc來分配記憶體,而malloc都基於brk()和sbrk()。

 #include <unistd.h>

 int brk(void *end_data_segment);

 int *sbrk(intptr_t increment);

brk()系統呼叫會將program break設定為end_data_segment的位置。成功呼叫返回0,失敗返回-1。

sbrk()系統呼叫會將program break原來的位置增加increment的大小。成功呼叫返回原來program break的位置,失敗返回(void *)-1。

PS:sbrk(0)返回program break的當前位置。

malloc()函式,C使用該函式在堆上分配和釋放記憶體。

 #include <stdlib.h>

 void *malloc(size_t size);

malloc分配size位元組大小的記憶體。並返回指向新分配的記憶體的起始位置的指標,該記憶體未經初始化;失敗返回NULL。

通常對返回的指標進行顯式型別轉換來獲得自己想要的型別的指標。

實際上每次呼叫malloc分配記憶體時,會額外分配多幾個位元組來記錄這塊記憶體的大小。(如下圖所示)

free()函式用來釋放記憶體塊。

 #include <stdlib.h>

 void free(void *ptr);

free釋放ptr指向的記憶體塊,ptr必須是malloc、calloc、realloc返回的指標。

free不會降低program break的位置,而是將該記憶體新增到空閒記憶體列表,用於以後malloc使用。

PS:不能對已經呼叫過free函式的指標,再次呼叫free,這樣會產生錯誤。

因為malloc分配後的記憶體會有記憶體塊的長度,所以free會知道這塊記憶體的大小,從而準確的將記憶體塊釋放,並放入空閒記憶體塊列表中。

PS:因此不能用free隨便釋放不是malloc返回的指標。

經過free釋放後的記憶體塊結構如下:

其實malloc呼叫是先查詢空閒記憶體塊列表,找到合適的記憶體塊。如果找不到合適的記憶體塊就呼叫sbrk()來分配更多的記憶體,為了減少呼叫sbrk的次數,會分配比size大小更多的記憶體來增加program break的位置,超出size大小的記憶體塊會放到空閒記憶體列表。

calloc()函式可以對一組相同的物件分配記憶體。

#include <stdlib.h>

void *calloc(size_t numitems, size_t size);

numitems指定了物件的數量,size指定了每個物件的大小。成功呼叫返回記憶體塊的起始地址,失敗返回NULL。malloc返回的記憶體不會初始化,而calloc返回的記憶體塊是已初始化。

realloc()函式可以調整一塊記憶體的大小。

 #include <stdlib.h>

 void *realloc(void *ptr, size_t size);

ptr是需要調整大小的記憶體塊的指標, size是所需調整大小的期望值。

成功呼叫會返回指向調整後記憶體塊的指標(位置可能不同),失敗返回NULL。

練習:

7-1. 修改程式清單7-1中的程式,在每次執行malloc()後打印出program break的當前至。指定一個較小的記憶體分配尺寸來執行該程式。這將證明malloc不會在每次呼叫時都會呼叫sbrk()來調整program break的位置,而是週期性地分大塊記憶體,並從中將小片記憶體返回給呼叫者。

程式清單7-1:

 /*
* =====================================================================================
*
* Filename: free_and_sbrk.c
*
* Description:
*
* Version: 1.0
* Created: 2014年03月19日 11時37分09秒
* Revision: none
* Compiler: gcc
*
* Author: alan (), [email protected]
* Organization:
*
* =====================================================================================
*/ #include "tlpi_hdr.h" #define MAX_ALLOCS 1000000 int main(int argc, char *argv[]){
char *ptr[MAX_ALLOCS];
int freeStep, freeMin, freeMax, blockSize, numAllocs, j; printf("\n"); if(argc < || strcmp(argv[], "--help") == )
usageErr("%s num-allocs blocksize [step [min [max]]]\n", argv[]); numAllocs = getInt(argv[], GN_GT_0, "num-allocs"); if(numAllocs > MAX_ALLOCS)
cmdLineErr("num-allocs > %d\n", MAX_ALLOCS); blockSize = getInt(argv[], GN_GT_0 | GN_ANY_BASE, "blocksize"); freeStep = (argc > ) ? getInt(argv[], GN_GT_0, "step") : ;
freeMin = (argc > ) ? getInt(argv[], GN_GT_0, "min") : ;
freeMax = (argc > ) ? getInt(argv[], GN_GT_0, "max") : numAllocs; if(freeMax > numAllocs)
cmdLineErr("free-max > num-allocs\n"); printf("Initial program break: %10p\n", sbrk()); printf("Allocing %d*%d bytes\n", numAllocs, blockSize); for(j = ; j < numAllocs; j++){
ptr[j] = malloc(blockSize);
if(ptr[j] == NULL)
errExit("malloc");
} printf("Program break is now: %10p\n", sbrk()); printf("Freeing blocks from %d to %d in steps of %d\n", freeMin, freeMax, freeStep);
for(j = freeMin-; j < freeMax; j += freeStep)
free(ptr[j]); printf("After free(), program break is %10p\n", sbrk()); exit(EXIT_SUCCESS);
}
 /*
* =====================================================================================
*
* Filename: free_and_sbrk.c
*
* Description:
*
* Version: 1.0
* Created: 2014年03月19日 11時37分09秒
* Revision: none
* Compiler: gcc
*
* Author: alan (), [email protected]
* Organization:
*
* =====================================================================================
*/ #include "tlpi_hdr.h" #define MAX_ALLOCS 1000000 int main(int argc, char *argv[]){
char *ptr[MAX_ALLOCS];
int freeStep, freeMin, freeMax, blockSize, numAllocs, j; printf("\n"); if(argc < || strcmp(argv[], "--help") == )
usageErr("%s num-allocs blocksize [step [min [max]]]\n", argv[]); numAllocs = getInt(argv[], GN_GT_0, "num-allocs"); if(numAllocs > MAX_ALLOCS)
cmdLineErr("num-allocs > %d\n", MAX_ALLOCS); blockSize = getInt(argv[], GN_GT_0 | GN_ANY_BASE, "blocksize"); freeStep = (argc > ) ? getInt(argv[], GN_GT_0, "step") : ;
freeMin = (argc > ) ? getInt(argv[], GN_GT_0, "min") : ;
freeMax = (argc > ) ? getInt(argv[], GN_GT_0, "max") : numAllocs; if(freeMax > numAllocs)
cmdLineErr("free-max > num-allocs\n"); printf("Initial program break: %10p\n", sbrk()); printf("Allocing %d*%d bytes\n", numAllocs, blockSize); for(j = ; j < numAllocs; j++){
ptr[j] = malloc(blockSize);
if(ptr[j] == NULL)
errExit("malloc");
printf("After malloc(), program break is: %10p\n", sbrk());
} printf("Program break is now: %10p\n", sbrk()); printf("Freeing blocks from %d to %d in steps of %d\n", freeMin, freeMax, freeStep);
for(j = freeMin-; j < freeMax; j += freeStep)
free(ptr[j]); printf("After free(), program break is %10p\n", sbrk()); exit(EXIT_SUCCESS);
}

測試結果:

lancelot@debian:~/Code/tlpi$ ./-   

Initial program break:           0x1913000
Allocing * bytes
After malloc(), program break is: 0x1934000
After malloc(), program break is: 0x1934000
After malloc(), program break is: 0x1934000
After malloc(), program break is: 0x1934000
After malloc(), program break is: 0x1934000
After malloc(), program break is: 0x1934000
After malloc(), program break is: 0x1934000
After malloc(), program break is: 0x1934000
After malloc(), program break is: 0x1934000
After malloc(), program break is: 0x1934000
After malloc(), program break is: 0x1934000
After malloc(), program break is: 0x1934000
After malloc(), program break is: 0x1934000
After malloc(), program break is: 0x1934000
After malloc(), program break is: 0x1934000
Program break is now: 0x1934000
Freeing blocks from to in steps of
After free(), program break is 0x1934000

可以清楚的看得出來,記憶體塊只是呼叫了一次sbrk()來改變program break的位置,分配15塊10個位元組的記憶體塊,只是第一次的時候呼叫了sbrk分配了1000個位元組的記憶體塊,並將990個位元組大小的記憶體塊放到空閒記憶體塊列表,供以後malloc的呼叫使用。。。。