系统调用与内存管理(sbrk、brk、mmap、munmap)(转)
一、系统调用(System Call):
在Linux中,4G内存可分为两部分——内核空间1G(3~4G)与用户空间3G(0~3G),我们通常写的C代码都是在对用户空间即0~3G的内存进行操作。而且,用户空间的代码不能直接访问内核空间,因此内核空间提供了一系列的函数,实现用户空间进入内核空间的接口,这一系列的函数称为系统调用(System Call)。比如我们经常使用的open、close、read、write等函数都是系统级别的函数(man 2 function_name),而像fopen、fclose、fread、fwrite等都是用户级别的函数(man 3 function_name)。不同级别的函数能够操作的内存区域自然也就不同。
我们用一幅图来描述函数的调用过程:
对于C++中new与delete的底层则是用malloc和free实现。而我们所用的malloc()、free()与内核之间的接口(桥梁)就是sbrk()等系统函数;当然我们也可以直接调用系统调用(系统函数),达到同样的作用。我们可以用下面这幅图来描述基本内存相关操作之间的关系:
虽然使用系统调用会带来一定的好处,但是物极必反,系统调用并非能频繁使用。由于程序由用户进入内核层时,会将用户层的状态先封存起来,然后到内核层运行代码,运行结束以后,从内核层出来到用户层时,再把数据加载回来。因此,频繁的系统调用效率很低。今天我们就系统调用层面来对内存操作做进一步的了解。
二、内存管理(Memory Management)系统调用:
1、brk()与sbrk():
(1)、函数原型与实现:
//函数原型:
#include<unistd.h>
int brk(void * addr);
void * sbrk(intptr_t increment);
由于sbrk()与brk()这两个系统函数有点所谓怪异,我们先来看看man手册对于sbrk()与brk()的描述:
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.
RETURN VALUE
On success, brk() returns zero. On error, -1 is returned, and errno
is set to ENOMEM.
On success, sbrk() returns the previous program break. (If the break
was increased, then this value is a pointer to the start of the newly
allocated memory). On error, (void *) -1 is returned, and errno is
set to ENOMEM.
描述:
brk()和sbrk()改变程序间断点的位置。程序间断点就是程序数据段的结尾。(程序间断点是为初始化数据段的起始位置).通过增加程序间断点进程可以更有效的申请内存 。当addr参数合理、系统有足够的内存并且不超过最大值时brk()函数将数据段结尾设置为addr,即间断点设置为addr。sbrk()将程序数据空间增加increment字节。当increment为0时则返回程序间断点的当前位置。
返回值:
brk()成功返回0,失败返回-1并且设置errno值为ENOMEM(注:在mmap中会提到)。
sbrk()成功返回之前的程序间断点地址。如果间断点值增加,那么这个指针(指的是返回的之前的间断点地址)是指向分配的新的内存的首地址。如果出错失败,就返回一个指针并设置errno全局变量的值为ENOMEM。
总结:
这两个函数都用来改变 “program break” (程序间断点)的位置,改变数据段长度(Change data segment size),实现虚拟内存到物理内存的映射。
brk()函数直接修改有效访问范围的末尾地址实现分配与回收。sbrk()参数函数中:当increment为正值时,间断点位置向后移动increment字节。同时返回移动之前的位置,相当于分配内存。当increment为负值时,位置向前移动increment字节,相当与于释放内存,其返回值没有实际意义。当increment为0时,不移动位置只返回当前位置。参数increment的符号决定了是分配还是回收内存。而关于program break的位置如图所示:
(2)、简单测试:
对于分配好的内存,我们只要有其首地址old与长度MAX*MAX即可不越界的准确使用(如下图所示),其效果与malloc相同,只不过sbrk()与brk()是C标准函数的底层实现而已,其机制较为复杂(测试中,死循环是为了查看maps文件,不至于进程消亡文件随之消失)。
虽然,sbrk()与brk()均可分配回收兼职,但是我们一般用sbrk()分配内存,而用brk()回收内存,上例中回收内存可以这样写:
int err = brk(old);
/**或者brk(p);效果与sbrk(-MAX*MAX);是一样的,但brk()更方便与清晰明了。**/
if(-1 == err){
perror("brk");
exit(EXIT_FAILURE);
}
2、mmap()与munmap():
mmap函数(地址映射):mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零(Linux堆空间未使用内存均清零)。这里我们只研究mmap的内存映射,而暂时不讨论文件方面的问题。关于mmap的文件映射的更详细的内容可参考认真分析mmap:是什么 为什么 怎么用
//函数原型:
#incldue<sys/mman.h>
void * mmap(void * addr, size_t length,int prot,int flags,int fd,off_t offset);
参数:
(1)、addr:
起始地址,置零让系统自行选择并返回即可.
(2)、length:
长度,不够一页会自动凑够一页的整数倍,我们可以宏定义#define MIN_LENGTH_MMAP 4096为一页大小
(3)、prot:
读写操作权限,PROT_READ可读、PROT_WRITE可写、PROT_EXEC可执行、PROT_NONE映射区域不能读取。(注意PROT_XXXXX与文件本身的权限不冲突,如果在程序中不设定任何权限,即使本身存在读写权限,该进程也不能对其操作)
(4)、flags常用标志:
①MAP_SHARED【share this mapping】、MAP_PRIVATE【Create a private copy-on-write mapping】
MAP_SHARED只能设置文件共享,不能地址共享,即使设置了共享,对于两个进程来说,也不会生效。而MAP_PRIVATE则对于文件与内存都可以设置为私有。
②MAP_ANON【Deprecated】、MAP_ANONYMOUS:匿名映射,如果映射地址需要加该参数,如果不加默认映射文件。MAP_ANON已经过时,只需使用MAP_ANONYMOUS即可
(5)、文件描述符:fd
(6)、文件描述符偏移量:offset
(fd和offset对于一般性内存分配来说设置为0即可)
返回值:
失败返回MAP_FAILED,即(void * (-1))并设置errno全局变量。
成功返回指向mmap area的指针pointer。
常见errno错误:
①ENOMEM:内存不足;
②EAGAIN:文件被锁住或有太多内存被锁住;
③EBADF:参数fd不是有效的文件描述符;
④EACCES:存在权限错误,。如果是MAP_PRIVATE情况下文件必须可读;使用MAP_SHARED则文件必须能写入,且设置prot权限必须为PROT_WRITE。
⑤EINVAL:参数addr、length或者offset中有不合法参数存在。
munmap函数:解除映射关系
int munmap(void * addr, size_t length);//addr为mmap函数返回接收的地址,length为请求分配的长度。
这张图描述了mmap内存地址映射的位置关系(栈区以上为内核空间)。关于这一点我们可以作以简单的测试(我采用MIN_LENGTH_MMAP宏,当然你也可以用多少申请多少,系统总是以最小1页来映射的,关于内存分页与虚拟地址映射可参考Linux系统内存管理与内存分页机制 ):
mmap映射的地址处于堆区与栈区中间,malloc映射的堆区内存为33页(最小映射大小),而mmap映射的内存为3页,也是4096B的整数倍。
---------------------
https://blog.csdn.net/Apollon_krj/article/details/54565768
系统调用与内存管理(sbrk、brk、mmap、munmap)(转)的更多相关文章
- Linux系统调用之内存管理
brk 改变数据段空间的分配 sbrk 参见brk mlock 内存页面加锁 munlock 内存页面解锁 mlockall 调用进程所有内存页面加锁 munlockall 调用进程所有内存页面解锁 ...
- Linux内存管理 (8)malloc
专题:Linux内存管理专题 关键词:malloc.brk.VMA.VM_LOCK.normal page.special page. 每章问答: malloc()函数是C函数库封装的一个核心函数,对 ...
- 【ARM-Linux开发】Linux内存管理:ARM Memory Layout以及mmu配置
原文:Linux内存管理:ARM Memory Layout以及mmu配置 在内核进行page初始化以及mmu配置之前,首先需要知道整个memory map. 1. ARM Memory Layout ...
- 动态内存管理详解:malloc/free/new/delete/brk/mmap
c++ 内存获取和释放 new/delete,new[]/delete[] c 内存获取和释放 malloc/free, calloc/realloc 上述8个函数/操作符是c/c++语言里常用来做动 ...
- 动态内存管理:malloc/free/new/delete/brk/mmap
这是我去腾讯面试的时候遇到的一个问题——malloc()是如何申请内存的? c++ 内存获取和释放 new/delete,new[]/delete[] c 内存获取和释放 malloc/free, c ...
- Linux内存管理 (9)mmap(补充)
之前写过一篇简单的介绍mmap()/munmap()的文章<Linux内存管理 (9)mmap>,比较单薄,这里详细的梳理一下. 从常用的使用者角度介绍两个函数的使用:然后重点是分析内核的 ...
- 转:Linux内存管理之mmap详解
一. mmap系统调用 1. mmap系统调用 mmap将一个文件或者其它对象映射进内存.文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零.munmap执行相 ...
- [转载] Linux内存管理之mmap详解
转载自http://blog.chinaunix.net/uid-26669729-id-3077015.html 一. mmap系统调用 1. mmap系统调用 mmap将一个文件或者其它对象映射进 ...
- Linux内存管理 (9)mmap
专题:Linux内存管理专题 关键词:文件映射.匿名映射.私有映射.共享映射 mmap/munmap是常用的一个系统调用,使用场景是:分配内存.读写大文件.连接动态库文件.多进程间共享内存. 更详细解 ...
随机推荐
- 一 :了解MVC
介绍 1. ASP.NET WebForm和ASP.NET MVC是并行的关系.都是属于.NET框架下的子框架. 2. MVC项目常用模板 空模板 : 不包含MVC目录结构,需要自己添加. 基本模 ...
- 01_日志采集框架Flume简介及其运行机制
离线辅助系统概览: 1.概述: 在一个完整的大数据处理系统中,除了hdfs+mapreduce+hive组成分析系统的核心之外,还需要数据采集.结果数据导出. 任务调度等不可或缺的辅助系统,而这些辅助 ...
- PAT Basic 1052 卖个萌 (20 分)
萌萌哒表情符号通常由“手”.“眼”.“口”三个主要部分组成.简单起见,我们假设一个表情符号是按下列格式输出的: [左手]([左眼][口][右眼])[右手] 现给出可选用的符号集合,请你按用户的要求输出 ...
- bat 获取当前文件夹的文件名
bat 获取当前文件夹的文件名 @echo off pushd %1 & for %%i in (.) do set curr=%%~ni echo %curr% pause
- JavaScript教程——函数(arguments 对象)
arguments 对象 定义 由于 JavaScript 允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数.这就是arguments对象的由来. arguments对象包含了 ...
- duilib学习领悟(1)
学习duilib已经有一段时间,一直没时间写总结,今天得出空来,写写心得体会! 由于本人知识有限,若有错误地方,望批评指正.多谢.! 初识duilib 刚开始接触duilib的时候,觉的他好神奇,整个 ...
- flask调试模式
想要启用调试模式,发现安装目前网上流行的两种方式均无法在Pycharm中打开调试模式. 1)直接在对象上设置 flask 更新到1.0以后 不支持使用debug =True 来开启调试模式了. Pri ...
- django.core.exceptions.ImproperlyConfigured: The included URLconf 's9luffycity.urls' does not appear to have any patterns in it. If you see valid patterns in the file then the issue is probably caused
出现问题: $ python manage.py runserver 启动项目报错时候 raise ImproperlyConfigured(msg.format(name=self.urlconf_ ...
- 题解 [CF961G] Partitions
题面 解析 首先我们观察这个定义, 可以发现每个元素在统计答案时是平等的, 也就是单个元素的权值对答案没有特别的影响. 设元素权值为\(w[i]\), 那么我们就可以知道答案是\(\sum_{i=1} ...
- MFC 画字体DrawText()或TextOut(),CFont字体样式类
新建单个文档的MFC应用程序,类视图——View项的属性——消息,WM_PAINT,创建OnPaint()函数 void CMFCApplication27View::OnPaint() { CPai ...