【发布时间】:2011-12-30 16:13:47
【问题描述】:
在Linux x86-64环境下,整个进程是分配在虚拟内存页上的吗?整个过程是指文本、数据、bss、堆和堆栈?
另外,当 libc 调用 Brk 时,内核是否返回由虚拟内存管理器通过页面管理的内存?
最后,进程能否在堆上获取内存,这不是由虚拟内存管理器管理的,换句话说,进程能否访问物理内存?
【问题讨论】:
在Linux x86-64环境下,整个进程是分配在虚拟内存页上的吗?整个过程是指文本、数据、bss、堆和堆栈?
另外,当 libc 调用 Brk 时,内核是否返回由虚拟内存管理器通过页面管理的内存?
最后,进程能否在堆上获取内存,这不是由虚拟内存管理器管理的,换句话说,进程能否访问物理内存?
【问题讨论】:
In Linux x86-64 environment, is the entire process allocated on virtual memory pages?
是的,所有进程都有一个虚拟地址空间,即有自己的页表和虚拟内存到物理内存的映射模式。
Also, when libc calls Brk, does the kernel returns memory that is managed via pages by virtual memory manager ?
是的,事实上,如果你没有破解操作系统内核,虚拟内存对你来说是透明的。
can a process get memory on heap, which is not managed by virtual memory manager, in other words, can a process get access to physical memory?
不,据我所知,除非您在没有操作系统支持的情况下运行程序,否则您无法管理物理内存。因为进程有自己的虚拟空间,所有与内存管理相关的操作都在虚拟内存上。
【讨论】:
一个进程有一个或多个任务(由内核调度),对于多线程进程是进程的线程(对于非线程进程是运行进程的任务),并且它有一个地址空间(以及其他一些资源,例如打开的文件描述符)。
当然,地址空间是在虚拟内存中。内核允许交换页面(例如磁盘的交换区域)。它尽量避免这样做(将页面交换到磁盘非常慢,因为磁盘访问时间是几十毫秒,而 RAM 访问时间是十分之一微秒)。
text & bss 等是虚拟内存段,是内存映射。您可以将进程空间视为内存映射。 mmap(2) 系统调用是修改它的方法。当一个可执行文件以execve 系统调用启动时,内核会建立一些映射(例如,文本、数据、bss、堆栈……)。 sbrk(2) 系统调用也会改变它。大多数malloc 实现使用mmap(至少对于足够大的区域),有时使用sbrk。
您可以通过使用 mlock(2) 系统调用将内存范围锁定到 RAM 来避免内存范围被换出,这通常需要 root 权限。它在实践中很少有用(除非您编写实时应用程序)。还有msync 系统调用(将内存刷新到磁盘),您当然可以将文件的一部分映射到虚拟内存(使用mmap),您可以使用mprotect(2) 更改保护,使用@987654327 删除映射@,使用mremap 扩展映射 - 特定于 Linux 的系统调用 -,您甚至可以捕获 SIGSEGV 信号并处理它(通常以特定于机器的方式)。 madvise(2) 系统调用使您能够使用提示调整分页。
您可以通过阅读/proc/1234/maps 文件(或/proc/1234/smaps)来了解pid 为1234 的进程的内存映射。 (在应用程序内部,您可以使用/proc/self/ 而不是/proc/1234/ ...)我建议您在终端中运行:
cat /proc/self/maps
它将显示运行cat 命令的进程的内存映射。您还可以使用pmap 实用程序。
最新的 linux 内核提供Adress Space Layout Randomization(因此在相同输入上运行相同程序的两个相似进程具有不同的mmap-ed 和malloc-ed 地址)。你可以通过/proc/sys/kernel/randomize_va_space禁用它
【讨论】:
除了在极少数情况下(uClinux),进程只能看到虚拟内存,由内核映射到物理内存。
可以要求内核进行特定的映射,为给定的虚拟地址提供可预测的物理地址;但是,您需要适当的能力来执行此操作,因为这会破坏流程分离。
在execve 上,当前映射被指定的 ELF 文件中的可加载段替换;这些被映射,以便从 ELF 文件加载引用的页面(还执行一些初始预读)。 brk系统调用主要是把最高地址的非可执行映射(不包括栈映射)扩展了几页,让进程可以访问更多的虚拟地址而不用发SIGSEGV。
堆一般由进程内部管理,但分配给堆对象的虚拟地址空间必须事先让虚拟内存管理器知道,才能创建映射。 malloc 通常会在其内部表中查找已映射且可用的区域,如果找不到,请使用 brk() 或 mmap() 创建更多映射。
【讨论】: