本文将以实验角度来认识进程的虚拟地址空间。
进程的虚拟地址空间就是进程如何在内存中存放的逻辑视图。通常该视图为进程从某一逻辑地址(如弟子0)开始,连续存放,如下图。物理地址可以按页帧来组织,且分配给进程的物理页帧也可能不是连续的。这就需要内存管理单元(MMU)将逻辑页映射到内存的物理页帧。
- Code segment: 存储除去共享库的静态代码
- Data segment : 存储除去共享库的全局变量
- Stack segment : 存储局部变量包括函数参数,也称为调用栈
- Heap segment, : 存储动态申请的变量
We will run a simple program and observe its memory layout.
我们写一个简单的程序来观测它的虚拟内存布局。
#include<stdio.h>
int main(int argc, char *argv[]){
printf("hello\n");
getchar();
return 0;
}
- 编译
gcc -o hello hello.c
- 执行
./hello
Ctrl Z
挂起程序cat /proc/ $(pgrep hello)/maps
查看虚拟内存空间布局
结果如下图所示:
00400000-00401000 r-xp 00000000 08:06 2490469 /home/susu/workspace/2015_OS_hw3/partA/hello.out
参数的涵义依次如下:
- start, end
- permision
- inode, image, offset
- major, minor
代码段&数据段
我们可以通过权限来区分虚拟内存区域。代码段一般有读与可执行权限,数据段会有读写权限。
代码段和数据段都是 0x1000 bytes,意味这它们在内存段中都只有一个 4KB 页。
下面分别表示代码段和数据段
00400000-00401000 r-xp 00000000 08:06 2490469 /home/susu/workspace/2015_OS_hw3/partA/hello.out
00600000-00601000 rw-p 00000000 08:06 2490469 /home/susu/workspace/2015_OS_hw3/partA/hello.out
栈段
栈段有读写权限与数据段相同
segment size = 0x7ffdf1cb1000 - 0x7ffdf1c90000 = 0x21000, 因此它由33个 4KB 页组成。
7ffdf1c90000-7ffdf1cb1000 rw-p 00000000 00:00 0 [stack]
共享内存段
共享内存段只有读权限
7fde68109000-7fde682a4000 r-xp 00000000 08:06 8787453 /usr/lib/libc-2.22.so
7fde682a4000-7fde684a3000 ---p 0019b000 08:06 8787453 /usr/lib/libc-2.22.so
7fde684a3000-7fde684a7000 r--p 0019a000 08:06 8787453 /usr/lib/libc-2.22.so
7fde684a7000-7fde684a9000 rw-p 0019e000 08:06 8787453 /usr/lib/libc-2.22.so
7fde684a9000-7fde684ad000 rw-p 00000000 00:00 0
7fde684ad000-7fde684cf000 r-xp 00000000 08:06 8787452 /usr/lib/ld-2.22.so
7fde68691000-7fde68694000 rw-p 00000000 00:00 0
7fde686cc000-7fde686ce000 rw-p 00000000 00:00 0
7fde686ce000-7fde686cf000 r--p 00021000 08:06 8787452 /usr/lib/ld-2.22.so
7fde686cf000-7fde686d0000 rw-p 00022000 08:06 8787452 /usr/lib/ld-2.22.so
lib.c
是标准 C 库,包含函数 printf(), fopen()
的实现。
ld.so 是动态链接装载器库,用来加载其他的共享库。