kernel笔记——进程地址空间

5330阅读 0评论2013-09-03 Godbach
分类:LINUX


下图是x86_64linux进程的默认内存布局形式:

下面逐一分析以上各个地址段的含义。

 

text 代码段

代码段,从虚拟内存地址00400000开始,使用pmap $$可以查看到,这个地址是固定的:

  1. linux # pmap $$
  2. 27729: bash
  3. START          SIZE   RSS   PSS  DIRTY SWAP PERM MAPPING
  4. 00400000       552K  480K  260K     0K   0K r-xp /bin/bash
  5. 00689000         4K    4K    4K     4K   0K r--p /bin/bash
  6. 0068a000        20K   20K   20K    20K   0K rw-p /bin/bash
  7. 0068f000      1420K 1356K 1356K  1356K   0K rw-p [heap]
  8. 7f4f47b72000    64K    4K    4K     0K   0K r-xp /usr/lib64/gconv/libGB.so
  9. ……
  10. 7f4f48c33000     4K    4K    4K     4K   0K rw-p [anon]
  11. 7fff0f0f1000    84K   20K   20K    20K   0K rw-p [stack]
  12. 7fff0f1ff000     4K    4K    0K     0K   0K r-xp [vdso]
  13. ffffffffff600000 4K    0K    0K     0K   0K r-xp [vsyscall]
  14. Total:       18944K 3256K 2225K  1580K   0K
  15. 1652K writable-private, 17052K readonly-private, 240K shared, and 3256K referenced

00400000地址段用于存放程序的可执行文件,fork一个子进程,之后调用execve加载可执行文件,execve即将文件加载到该段地址中:

  1. linux # strace ls
  2. execve("/bin/ls", ["ls"], [/* 65 vars */]) = 0
  3. brk(0) =0x618000
  4. mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) = 0x7f0422e2a000
  5. ……


data 数据段

数据段用于存放已初始化全局变量。

 

bss

该段用于存放全局的、但未初始化的变量。bss段与data段的区别是,编译时需为data段分配空间,而bss段不用。数据存放于bss段,减小了可执行程序的文件大小。

 

heap

堆,c库中的malloc调用就是从该段获取内存空间。

 

memory map

mmap系统调用可将文件映射入进程memory map地址空间。使用pmap $$查看,[heap]下面部分就是mmap区域,对于以上"pmap $$"输出:

  1. 7f4f47b72000  64K  4K  4K  0K  0K  r-xp        /usr/lib64/gconv/libGB.so

bash进程将/usr/lib64/gconv/libGB.so文件映射到以7f4f47b72000开头的地址段。

使用ldd命令,我们可以看到进程依赖的库文件,这些库文件编译过程中都要关联到进程的虚拟地址空间:

  1. linux # ldd /bin/bash
  2.   linux-vdso.so.1 => (0x00007fffc73ff000)
  3.   libreadline.so.5 => /lib64/libreadline.so.5 (0x00007f7effe50000)
  4.   libdl.so.2 => /lib64/libdl.so.2 (0x00007f7effc4c000)
  5.   libc.so.6 => /lib64/libc.so.6 (0x00007f7eff8ee000)
  6.   libncurses.so.5 => /lib64/libncurses.so.5 (0x00007f7eff6a6000)
  7.   /lib64/ld-linux-x86-64.so.2 (0x00007f7f00092000)

 

stack

存放局部变量,从高地址向低地址生长。

 

内核代码中,mm_struct结构用于描述一个进程的地址空间。

 

vm_area_struct用于描述一段地址,linux提供了/proc/PID/maps接口,我们可以通过该接口查询某进程的虚拟地址段:

  1. linux # cat /proc/$$/maps
  2. 00400000 - 00486000   r-xp 00000000 08:02 18104 /bin/bash
  3. 00586000 - 00586000   rw-p 00086000 08:02 18104 /bin/bash
  4. 0058b000 - 0073b000   rw-p 0058b000 00:00     0 [heap]
  5. 2b7c1ff67000 - 2b7c1ff82000 r-xp 00000000 08:02 12969 /lib64/ld-2.4.so
  6. ……
  7. 7fff8ab2d000 - 7fff8ab43000 rw-p 7fff8ab2d000 00:00 0 [stack]
  8. ffffffffff600000 - ffffffffffe00000 ---p 00000000 00:00 0 [vdso]

c库中的malloc底层通过mmapbrk实现内存申请。mmap可用于关联文件到进程的虚拟地址空间,也可用于申请匿名地址空间。

  1. void *mmap( void *addr, size_t length, int prot, int flags, int fd, off_t offset);

若指明fd就是关联文件到虚拟地址空间,没有指明就是申请匿名地址空间。

 

brk调用只是增加heap这一段虚拟内存空间,sbrk用于实际的内存申请。


Reference: Chapter 15 - The Process Address Space, Linux kernel development.3rd.Edition



上一篇:linux内核hlist分析
下一篇:What is Overcommit? And why is it bad?