第7章:編程
內存分配ide
經過增長堆的大小分配內存,經過提高program break位置的高度來分配內存。函數
基本學過C語言的都用過malloc來分配內存,而malloc都基於brk()和sbrk()。post
1 #include <unistd.h> 2 3 int brk(void *end_data_segment); 4 5 int *sbrk(intptr_t increment);
brk()系統調用會將program break設置爲end_data_segment的位置。成功調用返回0,失敗返回-1。測試
sbrk()系統調用會將program break原來的位置增長increment的大小。成功調用返回原來program break的位置,失敗返回(void *)-1。spa
PS:sbrk(0)返回program break的當前位置。指針
malloc()函數,C使用該函數在堆上分配和釋放內存。code
1 #include <stdlib.h> 2 3 void *malloc(size_t size);
malloc分配size字節大小的內存。並返回指向新分配的內存的起始位置的指針,該內存未經初始化;失敗返回NULL。htm
一般對返回的指針進行顯式類型轉換來得到本身想要的類型的指針。
實際上每次調用malloc分配內存時,會額外分配多幾個字節來記錄這塊內存的大小。(以下圖所示)
free()函數用來釋放內存塊。
1 #include <stdlib.h> 2 3 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()函數能夠調整一塊內存的大小。
1 #include <stdlib.h> 2 3 void *realloc(void *ptr, size_t size);
ptr是須要調整大小的內存塊的指針, size是所需調整大小的指望值。
成功調用會返回指向調整後內存塊的指針(位置可能不一樣),失敗返回NULL。
練習:
7-1. 修改程序清單7-1中的程序,在每次執行malloc()後打印出program break的當前至。指定一個較小的內存分配尺寸來運行該程序。這將證實malloc不會在每次調用時都會調用sbrk()來調整program break的位置,而是週期性地分大塊內存,並從中將小片內存返回給調用者。
程序清單7-1:
1 /* 2 * ===================================================================================== 3 * 4 * Filename: free_and_sbrk.c 5 * 6 * Description: 7 * 8 * Version: 1.0 9 * Created: 2014年03月19日 11時37分09秒 10 * Revision: none 11 * Compiler: gcc 12 * 13 * Author: alan (), alan19920626@gmail.com 14 * Organization: 15 * 16 * ===================================================================================== 17 */ 18 19 #include "tlpi_hdr.h" 20 21 #define MAX_ALLOCS 1000000 22 23 int main(int argc, char *argv[]){ 24 char *ptr[MAX_ALLOCS]; 25 int freeStep, freeMin, freeMax, blockSize, numAllocs, j; 26 27 printf("\n"); 28 29 if(argc < 3 || strcmp(argv[1], "--help") == 0) 30 usageErr("%s num-allocs blocksize [step [min [max]]]\n", argv[0]); 31 32 numAllocs = getInt(argv[1], GN_GT_0, "num-allocs"); 33 34 if(numAllocs > MAX_ALLOCS) 35 cmdLineErr("num-allocs > %d\n", MAX_ALLOCS); 36 37 blockSize = getInt(argv[2], GN_GT_0 | GN_ANY_BASE, "blocksize"); 38 39 freeStep = (argc > 3) ? getInt(argv[3], GN_GT_0, "step") : 1; 40 freeMin = (argc > 4) ? getInt(argv[4], GN_GT_0, "min") : 1; 41 freeMax = (argc > 5) ? getInt(argv[5], GN_GT_0, "max") : numAllocs; 42 43 if(freeMax > numAllocs) 44 cmdLineErr("free-max > num-allocs\n"); 45 46 printf("Initial program break: %10p\n", sbrk(0)); 47 48 printf("Allocing %d*%d bytes\n", numAllocs, blockSize); 49 50 for(j = 0; j < numAllocs; j++){ 51 ptr[j] = malloc(blockSize); 52 if(ptr[j] == NULL) 53 errExit("malloc"); 54 } 55 56 printf("Program break is now: %10p\n", sbrk(0)); 57 58 printf("Freeing blocks from %d to %d in steps of %d\n", freeMin, freeMax, freeStep); 59 for(j = freeMin-1; j < freeMax; j += freeStep) 60 free(ptr[j]); 61 62 printf("After free(), program break is %10p\n", sbrk(0)); 63 64 exit(EXIT_SUCCESS); 65 }
1 /* 2 * ===================================================================================== 3 * 4 * Filename: free_and_sbrk.c 5 * 6 * Description: 7 * 8 * Version: 1.0 9 * Created: 2014年03月19日 11時37分09秒 10 * Revision: none 11 * Compiler: gcc 12 * 13 * Author: alan (), alan19920626@gmail.com 14 * Organization: 15 * 16 * ===================================================================================== 17 */ 18 19 #include "tlpi_hdr.h" 20 21 #define MAX_ALLOCS 1000000 22 23 int main(int argc, char *argv[]){ 24 char *ptr[MAX_ALLOCS]; 25 int freeStep, freeMin, freeMax, blockSize, numAllocs, j; 26 27 printf("\n"); 28 29 if(argc < 3 || strcmp(argv[1], "--help") == 0) 30 usageErr("%s num-allocs blocksize [step [min [max]]]\n", argv[0]); 31 32 numAllocs = getInt(argv[1], GN_GT_0, "num-allocs"); 33 34 if(numAllocs > MAX_ALLOCS) 35 cmdLineErr("num-allocs > %d\n", MAX_ALLOCS); 36 37 blockSize = getInt(argv[2], GN_GT_0 | GN_ANY_BASE, "blocksize"); 38 39 freeStep = (argc > 3) ? getInt(argv[3], GN_GT_0, "step") : 1; 40 freeMin = (argc > 4) ? getInt(argv[4], GN_GT_0, "min") : 1; 41 freeMax = (argc > 5) ? getInt(argv[5], GN_GT_0, "max") : numAllocs; 42 43 if(freeMax > numAllocs) 44 cmdLineErr("free-max > num-allocs\n"); 45 46 printf("Initial program break: %10p\n", sbrk(0)); 47 48 printf("Allocing %d*%d bytes\n", numAllocs, blockSize); 49 50 for(j = 0; j < numAllocs; j++){ 51 ptr[j] = malloc(blockSize); 52 if(ptr[j] == NULL) 53 errExit("malloc"); 54 printf("After malloc(), program break is: %10p\n", sbrk(0)); 55 } 56 57 printf("Program break is now: %10p\n", sbrk(0)); 58 59 printf("Freeing blocks from %d to %d in steps of %d\n", freeMin, freeMax, freeStep); 60 for(j = freeMin-1; j < freeMax; j += freeStep) 61 free(ptr[j]); 62 63 printf("After free(), program break is %10p\n", sbrk(0)); 64 65 exit(EXIT_SUCCESS); 66 }
測試結果:
lancelot@debian:~/Code/tlpi$ ./7-1 15 10 2 Initial program break: 0x1913000 Allocing 15*10 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 1 to 15 in steps of 2 After free(), program break is 0x1934000
能夠清楚的看得出來,內存塊只是調用了一次sbrk()來改變program break的位置,分配15塊10個字節的內存塊,只是第一次的時候調用了sbrk分配了1000個字節的內存塊,並將990個字節大小的內存塊放到空閒內存塊列表,供之後malloc的調用使用。。。。