brk,sbrk-改变数据段的大小
所需头文件:
#include <unistd.h>
int brk(void *addr);
void *sbrk(intptr_t increment);
brk() and sbrk() change the location of the program break, which defines the end of the process's data segment (i.e., the program break is the first location after the end of the uninitialized data segment). Increasing the program break has the effect of allocating memory to the process; decreasing the break deallocates memory.
brk()和sbrk()修改program break的位置,program break是程序数据段的的尾部(这里说的program break是位于未初始化数据段(bss段)的尾部的开头位置),增加program break可以给process分配内存,减小program break可以释放内存
brk() sets the end of the data segment to the value specified by addr, when that value is reasonable, the system has enough memory, and the process does not exceed its maximum data size (see setrlimit(2)).
如果值是合理的,系统也有足够的内存,同时进程没有超过它的最大数据大小,brk()把数据段的尾部赋值给addr(这里说的数据段都是指堆区heap,不是真正的data segment)
sbrk() increments the program's data space by increment bytes. Calling sbrk() with an increment of 0 can be used to find the current location of the program break.
sbrk()通过increment byte来增加程序的数据空间, 用0作为increment的值来调用sbrk能够的得到当前programe break的位置
返回值:
On success, brk() returns zero. On error, -1 is returned, and errno is set to ENOMEM. (But see Linux Notes below.)
成功的时候,brk返回0,失败返回-1, errno被设置成ENOMEM
On success, sbrk() returns the previous program break. (If the break was increased, then this value is a pointer to the start of the newly allocated memory). On error, (void *) -1 is returned, and errno is set to ENOMEM.
成功的时候sbrk返回前一个program break(如果break增加了,这个值就是指向新分配的内存的起始处),错误返回(void *)-1,errno设置为ENOMEM
提示:
Avoid using brk() and sbrk(): the malloc(3) memory allocation package is the portable and comfortable way of allocating memory.
避免使用brk和sbrk:malloc函数在内存分配上更加方便和舒适
The return value described above for brk() is the behavior provided by the glibc wrapper function for the Linux brk() system call. (On most other implementations, the return value from brk() is the same; this return value was also specified in SUSv2.) However, the actual Linux system call returns the new program break on success. On failure, the system call returns the current break. The glibc wrapper function does some work (i.e.,checks whether the new break is less than addr) to provide the 0 and -1 return values described above.On Linux, sbrk() is implemented as a library function that uses the brk() system call, and does some internal bookkeeping so that it can return the old break value.
上面所说的brk返回值是glic对brk系统调用的封装(在其他大多数的实现下,这个返回值是一样的,在SUSv2里面同样是这样指定的),然而,实际上brk系统调用在成功的时候会返回新的program break,失败的时候会返回当前的program break,glibc的封装函数做了一些动作(检查新的break是否小于addr的)来返回前面所说的0或者-1,在linux里面,sbrk是用brk系统调用来实现的库函数,做了一些内部的动作来返回旧的break值(这里面需要注意的是library function跟system call的返回值并不一样,brk也是能拿到program break的,不然怎么实现sbrk的功能呢?)
下面贴出一个例子来说明sbrk的用法和与malloc之间的区别:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
//tell the initial program break
void *pbreak, *a, *b, *c;
pbreak= sbrk(0);
printf("pbreak = %p\n", pbreak);
//malloc 1 byte, check the program break
a = malloc(1);
pbreak = sbrk(0);
printf("pbreak = %p\n", pbreak);
//sbrk 2 byte, check the program break
b = sbrk(2);
pbreak = sbrk(0);
printf("pbreak = %p\n", pbreak);
//use the memory from sbrk, ensure it's the same as memory from malloc
//revert the sbrk memory, check the program break
memset(b, 0x00, 2);
strcpy((char *)b, "x");
printf("b = %s\n", (char *)b);
sbrk(-2);
pbreak = sbrk(0);
printf("pbreak = %p\n", pbreak);
//revert the malloc memory, check the program break
free(a);
a = NULL;
pbreak = sbrk(0);
printf("pbreak = %p\n", pbreak);
//malloc another 1 byte, check the program break
c = malloc(1);
pbreak = sbrk(0);
printf("pbreak = %p\n", pbreak);
//revert the malloc memory, check the program break
free(c);
pbreak = sbrk(0);
printf("pbreak = %p\n", pbreak);
return 0;
}
运行结果:
pbreak = 0x1020000
pbreak = 0x1041000
pbreak = 0x1041002
b = x
pbreak = 0x1041000
pbreak = 0x1041000
pbreak = 0x1041000
pbreak = 0x1041000
可以看到malloc分配的是一片内存(只要小于0x21000字节都是分配0x21000字节,所以malloc会有内存碎片),释放之后并不会立即归还给堆区,以后再次malloc的时候就使用那块还没有归还的内存,效率会更高一些,多少有一些slab的思想,sbrk就是需要多少byte就分配多少byte,释放掉之后马上返回给堆区,从上面提示可以看到,在平时工作中还是要尽量使用malloc,不要自行去管理堆区内存,至于为了么,就需要去问发明内存分配算法的先驱们了。。