菜鸟随笔---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()函数的学习与使用的主要内容,如果未能解决你的问题,请参考以下文章
malloc和free,brk和sbrk和mmap和munmap的使用和关系以及内存分配的原理
Linux系统下深究一个malloc/brk/sbrk新内存后的page fault问题