虚拟内存视角下的Linux进程 & 动态内存分配
Linux的虚拟内存系统
Linux为每个进程提供了一个虚拟地址空间。而这些地址空间被分为两部分:
进程虚拟内存部分我们已经很熟悉了,按照地址从低到高,他们分别是:
|
用户栈 |
| %rsp → |
|
|
共享库的内存映射区域 |
| brk → |
|
|
运行时的堆(通过malloc分配的) |
|
未初始化的数据(.bss) |
|
已初始化的数据(.data) |
| 0x400000 → |
代码(.text) |
内核虚拟内存可分为两部分:
- 内核中的代码和数据及数据结构
- 被映射到此的物理内存(Linux将一组连续的虚拟内存(大小等于系统DRAM总量)映射到物理内存,为内核提供一种便利的方法来访问物理内存中的任何位置)
| 与进程相关的数据结构(页表、task和mm结构、内核栈) |
每个进程都不相同 |
| 物理内存 |
每个进程都相同 |
| 内核代码和数据 |
每个进程都相同 |

Linux如何组织虚拟内存
Linux将虚拟内存组成成一些区域的集合。一个区域就是已分配的虚拟内存片段
这些片段通过一个结构链表被组织起来。(task_struct->mm_struct->mmap)

用户级内存映射
Linux 可以使用mmap函数来创建新的虚拟内存,并将对象映射到这些区域中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <unistd.h> #include <sys/mman.h>
void * mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *start, size_t length);
|
例子:将任意磁盘文件赋值到stdout
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include <csapp.h>
void mmapcopy(int fd, int size) { char *bufp;
bufp = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); Write(STDOUT_FILENO, bufp, size); return ; }
int main(int argc, char *argv[]) { struct stat stat; int fd;
if (argc != 2) { printf("usage: %s <filename>\n", argv[0]); exit(0); }
fd = Open(argv[1], O_RDONLY, 0); fstat(fd, &stat); mmapcopy(fd, stat.st_size); exit(0); }
|