谁在Linux中创建虚拟内存?

时间:2012-03-20 07:11:00

标签: linux-kernel virtual-memory

我知道内核负责将虚拟内存映射到实际内存。但是我想知道谁实际为进程创建了虚拟内存,如/ proc / pid / maps文件所示。

1)编译器/链接器是否为进程创建了一个虚拟内存区域,而内核只是将它映射到实际内存(因为虚拟内存区域并不重要,所有它都与映射有关)?

2)或者内核本身是否在分支进程时创建虚拟内存空间并将其映射到真实内存?

最后mmap系统调用做什么(1)或(2)?

2 个答案:

答案 0 :(得分:3)

你的断言实际上都是正确的(在某种程度上)。

对于可执行的ELF文件,链接器依赖于链接描述文件将虚拟空间中的地址分配给程序的每个符号(这些符号分组为具有起始地址和大小的部分)。您可以通过调用ld --verbose来查看使用的默认脚本。可以使用readelfobjdump等工具查看二进制文件的各个部分及其地址,例如readelf -l /bin/cat。然后,如果您运行cat /proc/self/maps,那么/bin/cat映射的地址应该匹配。所以execve内核系统调用会这样做:用一个新的地址空间替换当前进程的地址空间,作为参数给出的可执行文件被映射到该地址空间。

当然,如果为每个代码分配了一个静态地址,您将遇到共享库的问题。共享库使用与位置无关的代码,因此可以映射到进程地址空间中的任何位置。这里内核决定如何继续。

mmap不执行(1)或(2),它只是在地址空间的给定地址处映射文件的内存或部分(或让内核决定使用哪个地址)。实际上它用于映射程序使用的共享库。要查看方法,请运行strace /bin/true并查看如何首先调用execve以从二进制文件创建进程的地址空间,以及如何打开libc文件以及使用正确权限创建相关部分由程序加载器:

execve("/bin/true", ["/bin/true"], [/* 69 vars */]) = 0
...
open("/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
mmap(NULL, 3804080, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f224f351000
mprotect(0x7f224f4e8000, 2097152, PROT_NONE) = 0
mmap(0x7f224f6e8000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x197000) = 0x7f224f6e8000

以下文章也值得一读:

答案 1 :(得分:1)

内核是实际创建管理您在/ proc / pid / maps中看到的虚拟内存区域的实体。在保持每个进程状态(struct task_struct)的结构中,有一个struct mm_struct(在linux / sched.h中查看),特别是在struct vm_area_struct * mmap内。这是由映射到进程地址空间的所有内存区域(称为区域描述符)的内核维护的列表。调用mmap时,会在此列表中添加一个新元素,随后将显示在/ proc / pid / maps中。

请注意,大多数文件支持的区域,例如libc.so,在/ proc / pid / maps中列出,在进程启动时由动态链接器(ld.so)中的代码映射。

另请注意,在绝对必要之前,内核不会为这些区域中的地址创建虚拟物理映射。

希望这有帮助