大家都知道malloc是c中常用的內存操作函數,malloc動態的申請一塊指定大小的內存,方便存放數據。而brk/sbrk則是實現malloc的底層函數,其中brk是系統調用。brk和sbrk主要的工作是實現虛擬內存到內存的映射。很多人對這兩個函數不是很熟悉,本文主要介紹這兩個函數的用法。
首先介紹一下內存分配的過程。每個進程可訪問的虛擬內存空間為3G,但在程序編譯時,不可能也沒必要為程序分配這么大的空間,只分配并不大的數據段空間,程序中動態分配的空間就是從這一塊分配的。如果這塊空間不夠,malloc函數族(realloc,calloc等)就調用sbrk函數將數據段的下界移動,sbrk函數在內核的管理下將虛擬地址空間映射到內存,供malloc函數使用。
sbrk不是系統調用,是C庫函數。系統調用通常提供一種小功能,而庫函數通常提供比較復雜的功能。sbrk/brk是從堆中分配空間,本質是移動一個位置,向后移就是分配空間,向前移就是釋放空間,sbrk用相對的整數值確定位置,如果這個整數是正數,會從當前位置向后移若干字節,如果為負數就向前若干字節。在任何情況下,返回值永遠是移動之前的位置。
代碼演示如下:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
void *p, *old;
int r;
old = p = sbrk(0);
if (p == (void *)-1) {
printf("sbrk error\n");
return -1;
}
printf("cur pos:%p\n", p);
p = sbrk(1);
printf("%p\n", p);
p = sbrk(1);
printf("%p\n", p);
r = brk(old);
if (r == -1) {
printf("sbrk error\n");
return -1;
}
printf("original pos :%p\n", sbrk(0));
return 0;
}
程序執行結果如下:
cur pos:0x947c000
0x947c000
0x947c001
original pos :0x947c000
從程序的執行結果,可以看出,sbrk移動內存的單位是字節,且返回移動之前的值。
下面例子是利用brk和sbrk函數實現了打印1~100之間所有素數的功能,代碼如下:
#include
#include
#include
int judge(int num) {
int i;
for (i = 2; i < num; i++) {
if (num % i == 0) {
return 0;
}
}
return 1;
}
int main() {
int *p;
void *old;
int i;
old = sbrk(0);
if(old == (void *)-1) {
printf("sbrk error\n");
return -1;
}
p = (int *)old;
for (i = 1; i <= 100; i++) {
if (judge(i) == 1) {
p = sbrk(sizeof(int));
if (p == (int *)-1) {
printf("sbrk error\n");
return -1;
}
*p = i;
}
}
p = (int *)old;
while (p != sbrk(0)) {
printf("%d ", *p);
p++;
}
if (brk(old) == -1) {
printf("brk error\n");
return -1;
}
puts("");
return 0;
}
程序執行結果如下:
1 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97