malloc中的系统调用brk和mmap
程序员文章站
2022-03-07 15:14:54
malloc中的系统调用brk和mmap 环境 ubuntu14.04 malloc通过系统调用的方式从操作系统申请内存,malloc内部又通过系统调用brk()或mmap来申请内存的。入下图进程虚拟内存布局所示,mmap对应Memory Mapping Segment,brk对应Heap. brk ......
malloc中的系统调用brk和mmap
环境
-
ubuntu14.04
-
malloc通过系统调用的方式从操作系统申请内存,malloc内部又通过系统调用brk()或mmap来申请内存的。入下图进程虚拟内存布局所示,mmap对应memory mapping segment,brk对应heap.
brk
-
brk通过增加program break的位置(brk)从内核申请(非零值初始化)内存。一开始堆段(heap segment)的其实位置(start_brk)和结束位置(brk)指向同一个位置。
- 当aslr(address space layout randomization)关闭时,start_brk和brk同时指向data/bss段的结束位置(end_data)
- 当aslr打开时,start_brk和brk同时指向data/bss段的结束位置(end_data)再加上一个随机的brk偏移。
-
上面的进程虚拟内存布局展示了,start_brk是堆段的开始位置 ,brk(program break)是堆栈的结束位置。
例子
/* sbrk, brk 例子 */ #include <stdio.h> #include <unistd.h> #include <sys/types.h> int main() { void *curr_brk, *tmp_brk = null; printf("welcome to sbrk example:%d\n", getpid()); /* sbrk(0) 获取当前 program break 位置 */ tmp_brk = curr_brk = sbrk(0); printf("program break location1:%p\n", curr_brk); getchar(); /* 使用 brk 增加 program break 位置 */ brk(curr_brk+4096); curr_brk = sbrk(0); printf("program break location2:%p\n", curr_brk); getchar(); /* 使用 brk 减小 program break 位置 */ brk(tmp_brk); curr_brk = sbrk(0); printf("program break location3:%p\n", curr_brk); getchar(); return 0; }
-
在增加program break之前,输出如下:
-
start_brk=brk=end_data=0x602000
-
在增加program break之后,输入如下:
-
start_brk=end_data=0x602000,brk=0x603000.
-
可以观察到堆段
00602000-00603000 rw-p 00000000 00:00 0 [heap]
- 00602000-00603000是堆段的虚拟地址范围
- rw-p的标准含义是read、write、 noexecute、private
- 00000000 是文件偏移量,由于没有映射任何文件所以为0
- 00:00 是major/minor device number,由于没有映射任何文件所以为0
- 0是inode 也是没有映射任何文件所以为0
- 【heap】是堆段
mmap
- malloc使用mmap创建一个私有匿名的映射段,这个映射段的主要目的是申请一块(零值初始化的)新内存,并且这块内存只能被调用的这个进程独占使用。
/* 使用mmap系统调用做私有匿名映射的例子 */ #include <stdio.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> void static inline errexit(const char* msg) { printf("%s failed. exiting the process\n", msg); exit(-1); } int main() { int ret = -1; printf("welcome to private anonymous mapping example::pid:%d\n", getpid()); printf("before mmap\n"); getchar(); char* addr = null; addr = mmap(null, (size_t)132*1024, prot_read|prot_write, map_private | map_anonymous, -1, 0); if (addr == map_failed) errexit("mmap"); printf("after mmap\n"); getchar(); /* unmap mapped region. */ ret = munmap(addr, (size_t)132*1024); if(ret == -1) errexit("munmap"); printf("after munmap\n"); getchar(); return 0; }
-
调用mmap之前:可以看到,属于libc.so和ld-linux.so共享库的内存映射段。
-
调用mmap之后:如下我们可以看到,mmap映射的内存段已经从上图红色框内分配出去(0xe0000-0xbf000=0x21000).
- 调用munmap之后,如下输出可以看到mmap已经被解除映射了。
- 以上实现aslr是关闭的sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"
- 原文地址:
下一篇: golang开发及数字证书研究分享