背景知识
你需要了解 虚拟空间的构成。
而堆区的末尾(上面左方标记的 brk
),称为程序中断处(program break)。严格来说堆区是我们以程序的视角来看的,而以内存的视角来看,堆区、bss、data、rodata 均属于 data segment。
man 的 section 数字
- 1 - commands
- 2 - system calls
- 3 - library calls
- 4 - special files
- 5 - file formats and convertions
- 6 - games for linux
- 7 - macro packages and conventions
- 8 - system management commands
- 9 - others
sbrk 和 brk
brk 系列系统调用可以改变 data segment 的大小,也即可以改变堆内存的结束位置。
brk
: 设置 break 位置为给定的位置。- 返回值:
- 如果成功,返回 0
- 如果失败,返回 -1,且 errno 被设置为 ENOMEM
- 返回值:
sbrk
: 将 break 位置增加给定字节数。- 返回值:
- 如果成功,返回上一次 brk 的位置(可以调用
sbrk (0)
获取当前 brk 位置) - 如果失败,返回 -1,且 errno 被设置为 ENOMEM
- 如果成功,返回上一次 brk 的位置(可以调用
- 返回值:
#include <unistd.h>
int brk(void *addr);
void *sbrk(intptr_t increment);
mmap 和 munmap
mmap 的作用是将文件映射到进程的地址空间中,而 munmap 则是将映射的内存释放。
addr
: 创建映射的参考位置(若 NULL,则自动选取)(仅供参考,实际的位置可能高于它)length
: 映射的长度prot
: 保护等级PROT_NONE
: 不可访问PROT_READ
: 可读PROT_WRITE
: 可写PROT_EXEC
: 可执行
flags
: 映射方式AP_SHARED
: 共享映射,即允许其他进程访问AP_SHARED_VALIDATE
: 共享映射,并且确保其它 flags 都是有效的AP_PRIVATE
: 私有 COW 映射,即不允许其他进程访问AP_ANONYMOUS
: 匿名映射,即不创建文件映射,默认填充 0AP_FIXED
: 映射的位置固定,即不允许自动选取位置,强制使用给定 addrAP_GROWSDOWN
: 不要使用这个 FlagAP_DENYWRITE
: 不允许写入,即不允许其他进程写入映射区域AP_FIXED_NOREPLACE
: 同MAP_FIXED
,但不允许破坏已经存在的映射范围AP_HUGETLB
: 使用 Huge TLB 映射,即允许单个页面非常大- TLB 即虚拟地址 - 物理地址这个映射的缓存,如果我们要映射的文件特别大,则可以用大页映射,从而获得更好的 TLB 优化。详情看 HugeTLB Pages — The Linux Kernel documentation
MAP_SYNC
: 配合MAP_SHARED_VALIDATE
使用,同步写入,即写入时将数据同步到磁盘MAP_UNINITIALIZED
: 创建一个未初始化的映射,即不初始化数据,能够提高一些性能
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
int munmap(void *addr, size_t length);
mprotect
mprotect 的作用是修改映射区域的保护等级,即修改映射区域的访问权限。
prot flags:
PROT_NONE
不可访问PROT_READ
可读PROT_WRITE
可写PROT_EXEC
可执行PROT_SEM
别用PROT_SAO
别用PROT_GROWSUP
应用此保护直至映射区域的顶部PROT_GROWSDOWN
应用此保护直至映射区域的底部(用于常规的栈设计,向下增长)
#include <sys/mman.h>
int mprotect(void *addr, size_t len, int prot);