在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?
不,你不能,除非你不从OS支持运行您的程序管理按我的知识的物理内存。由于进程有其自己的虚拟空间,因此与内存管理相关的所有操作都在虚拟内存上。
进程有一个或多个任务(由内核调度),对于多线程进程来说是进程的线程(对于非线程进程来说是运行进程的任务),它有一个地址空间(和一些其他资源,例如打开的文件描述符)。
当然,地址空间是在虚拟内存中。内核被允许交换页面(例如磁盘的交换区域)。它尽量避免这样做(将页面交换到磁盘非常缓慢,因为磁盘访问时间在几十毫秒内,而RAM访问时间在十分之一微秒)。
文本 & BSS等都是虚拟存储器段,其是存储器映射。您可以将流程空间视为内存映射。系统调用mmap(2)是修改它的方法。当一个可执行文件以execve系统调用启动时,内核会建立一些映射(例如文本,数据,bss,堆栈等)。系统调用sbrk(2)也会改变它。大多数malloc
实现使用mmap
(至少对于足够大的区域),有时sbrk
。
使用系统调用mlock(2)系统调用(通常需要root权限),可以避免将内存范围锁定到RAM中,从而取消内存范围。在实践中很少有用(除非您编写实时应用程序)。系统调用还有msync系统调用(将内存刷新到磁盘),你当然可以将一部分文件映射到虚拟内存中(使用mmap
),可以用mprotect(2)更改保护,用munmap(2)更改保护,用mremap扩展映射 - 一个特定于Linux的系统调用 - ,你甚至可以捕获信号并处理它(通常是以一种特定于计算机的方式)。使用系统调用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文件加载引用的页面(也执行一些初始预读)。系统调用主要将具有最高地址(不包括堆栈映射)的不可执行映射扩展几页,允许进程访问更多虚拟地址,而不会发送SIGSEGV
。
堆一般由进程在内部进行管理,但为了创建映射,虚拟内存管理器必须事先知道分配给堆对象的虚拟地址空间。 malloc
通常会查看其已经映射和可用的区域的内部表格,如果找不到任何区域,则使用brk()
或mmap()
来创建更多映射。