虚拟内存与物理内存进行映射的过程被称为内存映射。内存映射是硬件(内存管理单元)级别的功能,必须按照硬件的规范设置好内存映射的关系,进程才能正常运行。
但内存映射并不能区分内存的用途,比如我们想知道虚拟内存区间0~2MB是用作存储数据还是存储指令,这就很难从内存映射中获取到相关信息。所以,Linux根据功能上的差异,来对虚拟内存空间进行管理。
之前我们说过,在32位的操作系统中,每个进程都拥有4GB的虚拟内存空间。Linux根据功能上的差异,把整个虚拟内存空间划分为多个不同区间,称为段。
从上图可以看出,进程的用户空间大小为3GB。Linux按照功能上的差异,把一个进程的用户空间划分为多个段,下面介绍一下各个段的作用:
数据段:用于存放已经初始化的全局变量或静态变量的段。如在C语言中,使用语句intglobal=10;定义的全局变量。
未初始化数据段:用于存放未初始化的全局变量或静态变量的段。如在C语言中,使用语句intglobal;定义的全局变量。
从上面的介绍可知,Linux按照功能上的差异,把虚拟内存空间划分为多个段。那么在内核中,是通过什么结构来管理这些段的呢?
vm_mm:指向进程的内存管理对象,每个进程都有一个类型为mm_struct的内存管理对象,用于管理进程的虚拟内存空间和内存映射等。
vm_next:Linux会通过链表把进程的所有虚拟内存区连接起来,这个字段用于指向下一个虚拟内存区。
vm_rb:某些场景中需要通过虚拟内存地址查找对应的虚拟内存区,为了加速查找过程,内核以虚拟内存地址作为key,把进程所有的虚拟内存区保存到一棵红黑树中,而这个字段就是红黑树的节点结构。
vm_ops:每个虚拟内存区都可以自定义一套操作接口,通过操作接口,能够让虚拟内存区实现一些特定的功能,比如:把虚拟内存区映射到文件。而vm_ops字段就是虚拟内存区的操作接口集,一般在创建虚拟内存区时指定。
从上图可以看出,内核通过一个链表和一棵红黑树来管理进程中所有的段。mm_struct结构的mmap字段就是链表的头节点,而mm_rb字段就是红黑树的根节点。
前面我们介绍了Linux会把虚拟内存地址划分为多个段,并且使用vm_area_struct结构来管理这些段。那么,这些虚拟内存区是怎么建立起来的呢?
ELF全称ExecutableandLinkableFormat,即可执行可链接文件格式。在Linux系统中,就是使用这种文件格式来存储一个可执行的应用程序。让我们来看一下ELF文件格式由哪些结构组成:
ELF头(ELFheader):描述应用程序的类型、CPU架构、入口地址、程序头表偏移和节头表偏移等等;
程序头表(Programheadertable):列举了所有有效的段(segments)和他们的属性,程序头表需要加载器将文件中的段加载到虚拟内存段中;
当内核加载一个应用程序时,就是通过读取ELF文件的信息,然后把文件中所有的段加载到虚拟内存的段中。ELF文件通过程序头表来描述应用程序中所有的段,表中的每一个项都描述一个段的信息。我们先来看看程序头表项的结构定义:
所以,程序加载器可以通过ELF头中获取到程序头表的偏移量,然后通过程序头表的偏移量读取到程序头表的数据,再通过程序头表来获取到所有段的信息。
要加载一个程序,需要调用execve系统调用来完成。我们来看看execve系统调用的调用栈:
从上面的调用者可以看出,execve系统调用最终会调用load_elf_binary函数来加载程序的ELF文件。
调用kernel_read函数从ELF文件中读取程序头表的数据,保存到elf_phdata变量中,程序头表的偏移量可以通过ELF头的e_phoff字段获取。
所以,把段加载到虚拟内存主要通过elf_map函数完成。我们来看看elf_map函数的调用栈:
从上面的调用者可以看出,elf_map函数最终会调用mmap_region来完成加载段到虚拟内存。我们分析以下mmap_region函数的实现:
调用kmem_cache_zalloc函数申请一个vm_area_struct(虚拟内存区)结构。
调用vma_link函数把vm_area_struct结构连接到虚拟内存区链表和红黑树中。
本文主要介绍了Linux内核是怎么加载应用程序,并且在虚拟内存中建立各个段的布局。本文主要关注的是虚拟内存布局的建立过程,但加载应用程序的很多细节都忽略了(如怎么设置进程入口),有兴趣可以自行查阅相关的资料和书籍。
金陵驿:大佬优质好文,必须点赞支持/jly_/article/details/?spm=...
金陵驿:大佬优质好文,必须点赞支持/jly_/article/details/?spm=...
金陵驿:大佬优质好文,必须点赞支持/jly_/article/details/
专家-百锦再:这篇文章的亮点在于作者对复杂问题的深入剖析,特别是在第二节中提到的潜在解决方案。这些方案不仅涵盖了各个层面的考虑,而且给出了可行的实施建议。这种全面性和可操作性使得这篇文章非常有价值。
1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。