内存
Last updated
Last updated
brk & sbrk
不属于Linux系统调用,而是C语言提供的。
函数原型:
这两个函数都用来改变 “program break” (程序间断点)的位置,改变数据段长度(Change data segment size),即 扩展heap的上界brk
,实现虚拟内存到物理内存的映射。 brk()
函数直接修改有效访问范围的末尾地址实现分配与回收。当addr
参数合理、系统有足够的内存并且不超过最大值时brk()
函数将数据段结尾设置为addr
,即间断点设置为addr
。sbrk()
函数中:当increment为正值时,间断点位置向后移动increment字节。同时返回移动之前的位置,相当于分配内存。当increment为负值时,位置向前移动increment字节,相当于释放内存,其返回值没有实际意义。当increment为0时,不移动位置只返回当前位置。参数increment的符号决定了是分配还是回收内存。
返回值:
brk()
成功返回0,失败返回-1并且设置errno
值为ENOMEM
。 sbrk()
成功返回之前的程序间断点地址。如果间断点值增加,那么这个指针(指的是返回之前的间断点地址)是指向分配的新的内存的首地址。如果出错失败,就返回一个指针并设置errno
全局变量的值为ENOMEM
。
sbrk()
与brk()
是C标准函数的底层实现,其机制较为复杂(测试中,死循环是为了查看maps文件,不至于进程消亡文件随之消失)。
虽然,sbrk()
与brk()
均可分配回收兼职,但是我们一般用sbrk()
分配内存,而用brk()
回收内存,上例中回收内存可以这样写:
mmap & munmap
mmap
函数第一种用法是映射磁盘文件到内存中,对该内存区域的存取即是直接对该文件内容的读写;而malloc
使用的mmap
函数的第二种用法,即匿名映射,匿名映射不映射磁盘文件,而是向映射区申请一块内存。
函数原型:
参数
说明
start
指向欲对应的内存起始地址,通常设为NULL,代表让系统自动选定地址,对应成功后该地址会返回。
length
代表将文件中多大的部分对应到内存。
prot
代表映射区域的保护方式,有下列组合:
PROT_EXEC
映射区域可被执行;
PROT_READ
映射区域可被读取;
PROT_WRITE
映射区域可被写入;
PROT_NONE
映射区域不能存取。
注意PROT_XXXXX
与文件本身的权限不冲突,如果在程序中不设定任何权限,即使本身存在读写权限,该进程也不能对其操作
flags
会影响映射区域的各种特性:
MAP_FIXED
如果参数 start 所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。
MAP_SHARED
对应射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。
MAP_PRIVATE
对应射区域的写入操作会产生一个映射文件的复制,即私人的"写入时复制" (copy on write)对此区域作的任何修改都不会写回原来的文件内容。
MAP_ANONYMOUS
建立匿名映射,此时会忽略参数fd
,不涉及文件,而且映射区域无法和其他进程共享。
MAP_DENYWRITE
只允许对应射区域的写入操作,其他对文件直接写入的操作将会被拒绝。
MAP_LOCKED
将映射区域锁定住,这表示该区域不会被置换(swap)。
在调用mmap()
时必须要指定MAP_SHARED
或 MAP_PRIVATE
。
fd
open()返回的文件描述词,代表欲映射到内存的文件。
offset
文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍。
返回值:失败返回
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中有不合法参数存在。
范例:利用mmap()
来读取/etc/passwd
文件内容:
在mmap
和munmap
执行过程的任何时刻,被映射文件的st_atime
可能被更新。若st_atime
字段在上述情况下没有得到更新,首次对映射区的第一个页索引时会更新该字段的值。
使用PROT_WRITE
和 MAP_SHARED
标志建立起来的文件映射,其st_ctime(c: change)
和 st_mtime(m: modification)
在对映射区写入之后与msync()[memory synchronize]
通过MS_SYNC
和 MS_ASYNC[memory asynchronize]
两个标志调用之前会被更新。
测试framebuffer
的小程序:显示红色方块。(对Framebuffer
进行读写可以直接操作显存,该程序需要在Linux的命令行模式下运行。)