brk/sbrk工作原理

来源:互联网 发布:教师网络学平台登录 编辑:程序博客网 时间:2024/05/17 05:17

http://blog.csdn.net/aspnet_lyc/article/details/20801957?utm_source=tuicool

malloc是c中常用的内存操作函数,malloc动态的申请一块指定大小的内存,方便存放数据

c++中的new实际上除了malloc分配内存之外还会调用构造函数初始化数据

而brk/sbrk则是实现malloc的底层函数,其中brk是系统调用。操作起来更为灵活,但很多人往往不容易理解。


[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. #include <unistd.h>   
  2.   
  3. int brk(void *addr);  
  4.   
  5. void *sbrk(intptr_t increment);  


返回值:
    brk()成功返回0,出错返回-1,并且errno被设置为ENOMEM
    sbrk()成功返回上一个程序结束点,出错返回-1,并且errno被设置为 ENOMEM


在文档中查看brk()/sbrk()的描述,粗略翻译如下:

DESCRIPTION
       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() 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)).

       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.

       brk()和sbrk()改变程序间断点的位置。程序间断点就是程序数据段的结尾。(程序间断点是为初始化数据段的起始位置).通过增加程序间断点进程可以更有效的申请内存

       当addr参数合理、系统有足够的内存并且不超过最大值时brk()函数将数据段结尾设置为addr,即间断点设置为addr
       sbrk()将程序数据空间增加increment字节。当increment为0时则返回程序间断点的当前位置。       


什么是程序间断点呢?
可以这样理解,进程在内存中被分为代码区,数据区,栈区和堆区。程序间断点指向堆区的起始位置。同时他也是数据段的结尾。
linux进程内存分布,地址从低到高依次是代码段,数据段,堆,栈,堆栈之间是mmap映射的共享内存空间以及共享库,再上是命令行参数,环境变量等,其中栈是从高地址向低地址分配,堆是从低地址向高地址分配。程序间断点就是当前进程映射虚拟地址的终止位置,通过移动这个位置来维护进程的映射的内存.而brk/sbrk的作用就是维护这个位置.


通过文档的描述可以总结出:
brk改变绝对位置
sbrk相对改变位置 >0则增加位置 <0则收缩位置

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. #include <unistd.h>   
  2. #include <stdio.h>   
  3. #include <stdlib.h>   
  4.   
  5. main()  
  6. {  
  7.     void *p;  
  8.     void *old;                       //存放原始间断点位置  
  9.     int  r;  
  10.   
  11.     old = p = sbrk(0);               //sbrk(0)返回当前的程序间断点  
  12.     if (p == (void*)-1)  
  13.         printf("sbrk error\n"), exit(-1);  
  14.     printf("当前程序间断点位置:%p\n", p);  
  15.     p = sbrk(1);                     //位置+1,但返回的是之前的位置而不是+1后的位置  
  16.     printf("%p\n", p);  
  17.     p = sbrk(1);                     //位置实际+2,但返回的是位置+1的值  
  18.     printf("%p\n", p);  
  19.   
  20.     r = brk(old);                    //将程序间断点设置为原始位置   
  21.     if (r == -1)  
  22.         printf("brk error\n"), exit(-1);  
  23.     printf("原始位置:%p\n", sbrk(0));//输出原始位置与第一次调用sbrk(0)的位置相同  
  24. }  


输出结果:



应用brk/sbrk小案例,求1-1000的素数.

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. #include <unistd.h>   
  2. #include <stdio.h>   
  3. #include <stdlib.h>   
  4.   
  5. int judge(int num)  
  6. {  
  7.     int i;  
  8.     for(i=2; i<num; i++) {  
  9.         if(num%i == 0)  
  10.             return 0;     
  11.     }  
  12.     return 1;  
  13. }  
  14.   
  15. main()  
  16. {  
  17.     int  *p;  
  18.     void *old;  
  19.     int  i;  
  20.   
  21.     old = sbrk(0);  
  22.     if (old == -1)  
  23.         printf("sbrk error\n"), exit(-1);  
  24.     p = (int*)old;  
  25.       
  26.     for(i=1; i<=1000; i++) {  
  27.         if(judge(i) == 1) {  
  28.             p = sbrk(4);  //int类型所以又移4个字节   
  29.             if (p == -1)  
  30.                 printf("brk error\n"), exit(-1);  
  31.             *p = i;  
  32.         }     
  33.     }  
  34.       
  35.     p = (int*)old;  
  36.     while(p != sbrk(0)) {  
  37.         printf("%d ", *p);  
  38.         p ++;  
  39.     }  
  40.                                           
  41.     if (brk(old) == -1)    //输出完毕,收回空间  
  42.         printf("brk error\n"), exit(-1);  
  43. }  

0 0
原创粉丝点击