关于sbrk/brk函数的使用

大家都知道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