菜鸟随笔(2)---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\n",*r);
          r++;
     }
     brk(p);//free
}

原文地址:https://www.cnblogs.com/1996-1-0-3-0/p/9267826.html

时间: 2024-11-09 10:06:51

菜鸟随笔(2)---brk()与sbrk()函数的学习与使用的相关文章

菜鸟随笔(3)---三种进程学习.孤儿进程.僵尸进程.守护进程

一只菜鸟横空出世,码农世界闯一闯,每天进展多一丢丢. 三种进程学习.孤儿进程.僵尸进程.守护进程 转自https://blog.csdn.net/believe_s/article/details/77040494 1.孤儿进程 如果父进程先退出,子进程还没退出那么子进程将被 托孤给init进程,这里子进程的父进程就是init进程(1号进程).其实还是很好理解的. // 父进程先子进程退出 // 子进程会被祖父进程接手并在后台运行,执行内部的代码 int main() { pid_t pid =

brk()和sbrk()函数的使用

根据上一篇文章继续解释 brk和sbrk的定义 在man手册中定义了这两个函数: 1 #include <unistd.h> 2 int brk(void *addr); 3 void *sbrk(intptr_t increment); 手册上说brk和sbrk会改变program break的位置,program break被定义为程序data segment的结束位置.感觉这句话不是很好理解,从下面程序地址空间的分布来看,data segment后面还有bss segment,显然和手册

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

转自:http://blog.csdn.net/kobbee9/article/details/7397010 brk和sbrk主要的工作是实现虚拟内存到内存的映射.在GNUC中,内存分配是这样的:       每个进程可访问的虚拟内存空间为3G,但在程序编译时,不可能也没必要为程序分配这么大的空间,只分配并不大的数据段空间,程序中动态分配的空间就是从这一块分配的.如果这块空间不够,malloc函数族(realloc,calloc等)就调用sbrk函数将数据段的下界移动,sbrk函数在内核的管理

brk()和sbrk()使用方法解析

brk() , sbrk() 的声明如下: [cpp] view plaincopy #include <unistd.h> int brk(void *addr); void *sbrk(intptr_t increment); 首先说明一点 sbrk()是函数库调用,brk()是系统调用 这两个函数都用来改变 "program break" (程序间断点)的位置,这个位置可参考下图: 如 man 里说的: 引用 brk()  and  sbrk() change the

brk 和 sbrk 区别

转自:https://www.cnblogs.com/chengxuyuancc/p/3566710.html brk和sbrk的定义,在man手册中定义了这两个函数: 1 #include <unistd.h> 2 int brk(void *addr); 3 void *sbrk(intptr_t increment); 手册上说brk和sbrk会改变program break的位置,program break被定义为程序data segment的结束位置.感觉这句话不是很好理解,从下面程

[Unity菜鸟] Unity鼠标双击,鼠标函数整理(未完)

1. 鼠标双击 ? 1 2 3 4 5 6 7 8 9 void OnGUI()    {        Event Mouse = Event.current;        if (Mouse.isMouse && Mouse.type == EventType.MouseDown && Mouse.clickCount == 2)        {            // 调用你的函数            print("Double Click&quo

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

brk 和 sbrk的使用: 作用:malloc的底层实现,用于分配开辟内存,但是brk是系统调用 而sbrk不是  ,sbrk调用了brk 用法: 特别注意 : brk返回值 0成功 -1 失败                         sbrk返回的是开辟之前的地址,错误返回-1                开辟后要brk(p)释放掉内存空间简单示例: 1 1 #include <stdio.h> 2 2 #include <unistd.h> 3 3 #include

Matlab中常见的神经网络训练函数和学习函数

一.训练函数 1.traingd Name:Gradient descent backpropagation (梯度下降反向传播算法 ) Description:triangd is a network training function that updates weight and bias values  according to gradient descent. 2.traingda Name:Gradient descent  with adaptive learning rate

初探C++函数模版学习笔记

泛型程序设计 特点:算法实现时不指定具体要操作的数据的类型.算法实现一遍但可适用于多种数据结构. 优势:减少重复代码的编写. 实现:大量编写模板, 使用模板的程序设计. 函数模版 为了交换两个int变量的值, 需要编写如下Swap函数: void Swap(int & x, int & y) { int tmp = x; x = y; y = tmp; } 为了交换两个double型变量的值, 还需要编写如下Swap函数: void Swap(double & x, double