brk和sbrk的定义

  在man手册中定义了这两个函数:

 #include <unistd.h>
int brk(void *addr);
void *sbrk(intptr_t increment);

  手册上说brk和sbrk会改变program break的位置,program break被定义为程序data segment的结束位置。感觉这句话不是很好理解,从下面程序地址空间的分布来看,data segment后面还有bss segment,显然和手册说的不太一样。一种可能的解释就是手册中的data segment和下图中的data segment不是一个意思,手册中的data segment应该包含了下图中的data segment、bss segment和heap,所以program break指的就是下图中heap的结束地址。

  有了前面program break的概念后,我们来看下brk和sbrk的作用。brk通过传递的addr来重新设置program break,成功则返回0,否则返回-1。而sbrk用来增加heap,增加的大小通过参数increment决定,返回增加大小前的heap的program break,如果increment为0则返回program break。

  从上面的图可以看出heap的起始地址并不是bss segment的结束地址,而是随机分配的,下面我们用一个程序来验证下:

 #include <stdio.h>
#include <unistd.h> int bss_end; int main(void)
{
void *tret; printf("bss end: %p\n", (char *)(&bss_end) + );
tret = sbrk();
if (tret != (void *)-)
printf ("heap start: %p\n", tret);
return ;
}

  运行的结果为:

  从上面运行结果可以知道bss和heap是不相邻的,并且同一个程序bss的结束地址是固定的,而heap的起始地址在每次运行的时候都会改变。你可能会说sbkr(0)返回的是heap的结束地址,怎么上面确把它当做起始地址呢?由于程序开始运行时heap的大小是为0,所以起始地址和结束地址是一样的,不信我们可以用下面的程序验证下。

 #include <stdio.h>
#include <unistd.h>
#include <stdlib.h> int bss_end; int main(void)
{
void *tret;
char *pmem; printf("bss end: %p\n", (char *)(&bss_end) + );
tret = sbrk();
if (tret != (void *)-)
printf ("heap1 start: %p\n", tret); if (brk((char *)tret - ) == -)
printf("brk error\n"); tret = sbrk();
if (tret != (void *)-)
printf ("heap2 start: %p\n", tret); pmem = (char *)malloc();
if (pmem == NULL) {
perror("malloc");
exit (EXIT_FAILURE);
}
printf ("pmem:%p\n", pmem); tret = sbrk();
if (tret != (void *)-)
printf ("heap1 end: %p\n", tret); if (brk((char *)tret - ) == -)
printf("brk error\n"); tret = sbrk();
if (tret != (void *)-)
printf ("heap2 end: %p\n", tret);
return ;
}

  运行结果为:

  程序开始的时候打印出来heap的结束地址,并用这个地址减1来重新设置heap的结束地址,结果两次的结束地址居然是一样的,那说明这个结束地址就是heap的起始地址,再减小这个起始地址是不允许的,不过brk也不会报错。然后调用malloc获取内存,并打印出该内存的起始地址pmem,可以发现pmem与heap的起始地址相差8个字节,为什么会有8个字节没有?这8个字节应该是用来管理heap空间的(不深究)。最后再次获得heap的结束地址,并用这个地址减10来重新设置heap的结束地址,这下地址设置成功了。

堆的管理

  上面的函数我们其实很少使用,大部分我们使用的是malloc和free函数来分配和释放内存。这样能够提高程序的性能,不是每次分配内存都调用brk或sbrk,而是重用前面空闲的内存空间。brk和sbrk分配的堆空间类似于缓冲池,每次malloc从缓冲池获得内存,如果缓冲池不够了,再调用brk或sbrk扩充缓冲池,直到达到缓冲池大小的上限,free则将应用程序使用的内存空间归还给缓冲池。

  如果缓冲池需要扩充时,一次扩充多少呢?先运行下面的程序看看:

 #include <stdio.h>
#include <unistd.h>
#include <stdlib.h> int main(void)
{
void *tret;
char *pmem; tret = sbrk();
if (tret != (void *)-)
printf ("heap start: %p\n", tret); pmem = (char *)malloc(); //分配内存
if (pmem == NULL) {
perror("malloc");
exit (EXIT_FAILURE);
}
printf ("pmem:%p\n", pmem);
tret = sbrk();
if (tret != (void *)-)
printf ("heap size on each load: %p\n", (char *)tret - pmem);
free(pmem)
return ;
}

  运行结果如下:

  从结果可以看出调用malloc(64)后缓冲池大小从0变成了0x20ff8,将上面的malloc(64)改成malloc(1)结果也是一样,只要malloc分配的内存数量不超过0x20ff8,缓冲池都是默认扩充0x20ff8大小。值得注意的是如果malloc一次分配的内存超过了0x20ff8,malloc不再从堆中分配空间,而是使用mmap()这个系统调用从映射区寻找可用的内存空间。

参考

  http://blog.csdn.net/sgbfblog/article/details/7772153

理解brk和sbrk的更多相关文章

  1. brk 和 sbrk 区别

    转自:https://www.cnblogs.com/chengxuyuancc/p/3566710.html brk和sbrk的定义,在man手册中定义了这两个函数: 1 #include < ...

  2. Unix系统编程()brk,sbrk

    在堆上分配内存 进程可以通过增加堆的大小来分配内存,所谓堆是一段长度可变的连续虚拟内存,始于进程的未初始化数据段末尾,随着内存的分配和释放而增减.通常将堆的当前内存边界称为"program ...

  3. Linux中brk()系统调用,sbrk(),mmap(),malloc(),calloc()的异同【转】

    转自:http://blog.csdn.net/kobbee9/article/details/7397010 brk和sbrk主要的工作是实现虚拟内存到内存的映射.在GNUC中,内存分配是这样的:  ...

  4. brk(), sbrk() 用法详解

    brk() , sbrk() 的声明如下: #include <unistd.h> int brk(void *addr); void *sbrk(intptr_t increment); ...

  5. brk(), sbrk() 用法详解【转】

    转自:http://blog.csdn.net/sgbfblog/article/details/7772153 贴上原文地址,好不容易找到了:brk(), sbrk() -- 改变数据段长度 brk ...

  6. 系统调用与内存管理(sbrk、brk、mmap、munmap)(转)

    一.系统调用(System Call):在Linux中,4G内存可分为两部分——内核空间1G(3~4G)与用户空间3G(0~3G),我们通常写的C代码都是在对用户空间即0~3G的内存进行操作.而且,用 ...

  7. Linux内存分配小结--malloc、brk、mmap【转】

    转自:https://blog.csdn.net/gfgdsg/article/details/42709943 http://blog.163.com/xychenbaihu@yeah/blog/s ...

  8. brk和mmap(转)

    进程分配内存有两种方式,分别由两个系统调用完成:brk和mmap: 1.brk是将数据段的(.data)的最高地址指针_edata往高地址推 2.mmap是虚拟地址空间找一个空闲的虚拟内存 如果mal ...

  9. 转:如何实现一个malloc

    如何实现一个malloc 转载后排版效果很差,看原文!   任何一个用过或学过C的人对malloc都不会陌生.大家都知道malloc可以分配一段连续的内存空间,并且在不再使用时可以通过free释放掉. ...

随机推荐

  1. Redis集群最佳实践

    今天我们来聊一聊Redis集群.先看看集群的特点,我对它的理解是要需要同时满足高可用性以及可扩展性,即任何时候对外的接口都要是基本可用的并具备一定的灾备能力,同时节点的数量能够根据业务量级的大小动态的 ...

  2. openGL实现二维图形和三维图形

    openGL是一个强大的底层图形库,其命令最初的时候使用C语言实现的.openGL定义了一个图形程序接口,常用于制作处理三维图像,功能强大,调用方便,在图像处理十分受欢迎. 实现图形主要使用的是ope ...

  3. STM32之看门狗(独立与窗口)

    广大的互联网网友们,大家早上中午晚上好,我是某某某..对于狗..看过<忠犬八公>的我.无不深深的被狗的义气与灵气所震撼..我也觉得在所有mcu中用看门狗来形容让系统复位的功能是很恰当的.也 ...

  4. JQuery对象与DOM对象的区别与转换

      1.jQuery对象和DOM对象的区别 DOM对象,即是我们用传统的方法(javascript)获得的对象,jQuery对象即是用jQuery类库的选择器获得的对象; eg: var domObj ...

  5. QT 文件对话框(QFileDialog)

    1.选择文件(上传.打开...) QString QFileDialog::getOpenFileName( QWidget *parent = , //parent,用于指定父组件.注意,很多Qt组 ...

  6. String对象方法扩展

    /** *字符串-格式化 */ String.prototype.format = function(){ var args = arguments;//获取函数传递参数数组,以便在replace回调 ...

  7. webstorm快捷键

    webstorm应该是目前最强的js编辑器了,结合sublime text可以很效率的开发项目.今天整理了一些webstorm比较实用的快捷键: Ctrl+/ 或 Ctrl+Shift+/ 注释(// ...

  8. python之路 - 爬虫

    网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本.另外一些不常使用的名字还有蚂蚁.自动索引.模拟程序或者蠕 ...

  9. linux下Vim的使用

    在vim中移动光标跟其他的编辑器中有很大的区别,不过一旦学会了,就会飞速的在文本中移动 复制粘贴dd 删除光标所在行dw 删除一个字(word)x 删除当前字符X 删除前一个字符D 删除到行末yy 复 ...

  10. Visual Studio 2015 如何将全英界面转成中文

    1 启动VS2015程序,在菜单栏中找到tools 2 在弹出的下拉窗口中选中options 3 此时弹出的对话框,选中Environment下的international setting 4 点击获 ...