菜鸟随笔---brk()与sbrk()函数的学习与使用

Posted 1996-1-0-3-0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了菜鸟随笔---brk()与sbrk()函数的学习与使用相关的知识,希望对你有一定的参考价值。

一只菜鸟横空出世,码农世界闯一闯,每天进展多一丢丢。

 

brk()与sbrk()函数的学习与使用

brk()与sbrk()函数定义如下

#include <unistd.h>

int brk(boid *addr);

addr:把内存末尾指针设置为addr.返回值:0表示成功,非0表示失败

void *sbrk(intptr_t increment);

increment:把内存的末尾指针移动increment个字节。返回值:上次调用sbrk/brk的内存末尾指针。

 

内容摘选转自:https://blog.csdn.net/tiankaiying/article/details/8499496

虚拟内存的分配.
               栈:编译器自动生成代码维护
               堆:地址是否映射,映射的空间是否被管理.
         棧和堆这两个数据结构是系统管理的。
         这个时候就要使用brk/sbrk函数了。这两个函数都是我们自己申请一块内存,这块内存不再由系统托管。完完全全是我们自己管理。也就是说我们自己要负责这一块内存的使用和释放,系统不再负责了。
 1.brk/sbrk 内存映射函数 unix的函数
           问题1 怎么知道空闲空间?
             问题2 内核的内存分配方式?
                         
              每个进程可访问的虚拟内存空间为3G,但在程序编译时,不可能也没必要为程序分配这么大的空间,只分配并不大的数据段空间,程序中动态分配的空间就是从这 一块分配的。如果这块空间不够,malloc函数族(realloc,calloc等)就调用sbrk函数将数据段的下界移动,sbrk函数在内核的管理 下将虚拟地址空间映射到内存,供malloc函数使用。所以sbrk要分配新空间给进程。 
            内核数据结构mm_struct中的成员变量start_code和end_code是进程代码段的起始和终止地址, 
                                                                        start_data和 end_data是进程数据段的起始和终止地址,
                                                                        start_stack是进程栈段起始地址,
                                                                        start_brk是进程动态内存分配起始地址(堆的起始地址),
                                                                        还有一个 brk(堆的当前的终止地址),就是动态内存分配当前的终止地址。
C语言的动态内存分配基本函数是malloc(),在Linux上的基本实现是通过内核的brk系统调用。brk()是一个非常简单的系统调用,
brk只是简单地改变mm_struct结构的成员变量brk的值。
               
      分配释放内存:         
               int brk(void *end);//分配空间,释放空间 实际是改变end_ptr的值
                         移动访问的范围
                                   end_ptr > sbrk(0)  //分配
                                   end_ptr < sbrk(0) //释放
               void *sbrk(int size);//只做空间分配,返回分配空间的首地址
                        size = 0 得到大块空闲空间的首地址指针. 但这个指针没有映射还不能用
                             > 0 分配指定空间,end_ptr移动到末尾,每次分配从end_ptr开始,返回这片空间的首地址指针,并且把end_ptr指针位置+size
                            < 0 释放空间  返回释放的空间的end_ptr的地址(这个地址已经不能用了),并将空间指针回移。
               应用:
                         1.使用sbrk分配空间
                         2.使用sbrk得到没有映射的空间的虚拟地址.
                                   int *p = sbrk(0); //p这个指针还不能用,还没映射。
                                   *p = 40;//给没有映射的空间赋值,段错误。
                              如果参数不是0,就帮你映射size的空间,以页为单位的分配。 
                         3.使用brk分配空间
                                   int* p = sbrk(0);  // int* p = sbrk(9);这里的效果一样,因为后面brk又把末尾指针往前移动了。
                                   brk(p+1); //这里虽然只是加1个字节,但是映射了一个页4k。
                                   int* q = sbrk(0);
               //这时候返回的地址与p相差4个字节,按brk移动的字节数末尾,开始向高地址(未分配区)分配。brk指向的地方是标记为已经用的。
                                   *p=40;
                                   *(p+40)=60;//证明映射的不只1个字节,不会有段错误,但逻辑上不这么用
                                   brk + 链表结构管理 = malloc
                                   malloc+初始化 = new
                         4.使用brk释放空间

               理解:
                         sbrk(int  size)
                         sbrk与brk后台系统维护一个指针.
                         指针默认是null.
                         调用sbrk,判定指针是否是0,是:得到大块空闲空间的首地址初始化指针.
                                                                                                    同时把指针+size
                                                                                          否:返回指针,并且把指针位置+size
               应用案例:
                         写一个程序查找1-10000之间所有的素数.
                         并且存放到缓冲,然后打印.
                        
                         缓冲的实现使用sbrk/brk
                         流程:
                                   循环
                                             判定是否素数(isPrimer)
                                             是,分配空间存放
                                             不是,继续下步.
#include <stdio.h>
#include <unistd.h>
int isPrimer(int a)
{    
     int i;
     for(i=2;i<a;i++)
     {
          if(a%i==0)
          {
               return 1;              
          }
     }
     return 0;
}

main()
{
     int i=2;
     int b;
     int *r;
     int *p;
     p=sbrk(0); 
     r=p;
     for(;i<100;i++)
     {
          b=isPrimer(i);
          if(b==0)
          {
               brk(r+1); //末尾指针end_ptr=(r+1); 所以r被映射了。
               *r=i;
               r=sbrk(0);
          }
     }
     i=0;     r=p;
     while(r!=sbrk(0))
     {
          printf("%d ",*r);
          r++;
     }
     brk(p);//free

 

 

 






































































































以上是关于菜鸟随笔---brk()与sbrk()函数的学习与使用的主要内容,如果未能解决你的问题,请参考以下文章

brk 和 sbrk()的使用 及分配内存方式

02_brk/sbrk

malloc和free,brk和sbrk和mmap和munmap的使用和关系以及内存分配的原理

Linux系统下深究一个malloc/brk/sbrk新内存后的page fault问题

调用 malloc 函数并不总是在内部调用 sbrk 函数?

菜鸟随笔---read函数与fread函数的区别