在Linux中如何实现sbrk / brk?

我正在考虑Linux内核如何实现系统调用,我想知道是否有人可以给我一个关于sbrk / brk的工作方式的高级视图?

我已经查看了内核代码,但是有太多的内容,我不明白。 我希望从某人那里得到一个总结?

Solutions Collecting From Web of "在Linux中如何实现sbrk / brk?"

在一个非常高层次的视图中,Linux内核将一个进程可见的内存作为几个“内存区域”( struct vm_area_struct )进行跟踪。 还有一个结构,它代表了一个进程的整个地址空间( struct mm_struct )。 每个进程(除了一些内核线程)都只有一个struct mm_struct ,它指向所有可以访问的内存的struct vm_area_struct

sys_brk系统调用(在mm/mmap.c找到)可以简单地调整这些内存区域的一部分。 ( sbrkbrk周围的glibc包装)。 它通过比较brk地址的旧值(在struct mm_struct找到)和请求的值来实现。

首先看一下mmap系列函数会更简单一些,因为brk是一个特例。

您必须了解虚拟内存是如何工作的以及MMU映射如何与真实RAM相关。

真正的RAM被分成页面,传统上每个4KB。 每个进程都有它自己的MMU映射,这个映射给那个进程提供了一个线性的内存空间(在32位linux中是4GB)。 当然,并不是全部都是实际分配的。 起初,它几乎是空的,这是没有真正的页面与大多数地址相关联。

当进程遇到未分配的地址(试图读取,写入或执行)时,MMU产生一个错误(类似于中断),并调用VM系统。 如果它决定有一些RAM应该在那里,它将选择一个未使用的RAM页面并与该地址范围相关联。

这样,内核不关心进程如何使用内存,进程并不在乎有多少内存,它总是有相同的线性4GB的地址空间。

现在, brk/sbrk工作在一个稍微高一点的水平上:原则上任何内存地址'超出'该标记是无效的,如果访问将不会得到一个内存页,这个过程将被杀死。 用户空间库在此限制内管理内存分配,只有在需要时才要求内核增加内存分配。

但是,即使一个进程通过将brk设置为允许的最大值开始,也不会获得分配的真实RAM页面,直到开始访问所有内存地址。

那么从超高层次看,内核分配一个可分页的内存块,修改请求该块的进程的页表,使内存映射到进程的VA空间,然后返回地址。

Linux内核如何将内存传递给用户进程的一个关键概念是进程可用堆(数据段)从底部增长。 内核不跟踪单独的内存块,只是连续的内存块。 brk / sbrk系统调用会扩大进程的内存量,但是这个过程需要使用可用的块进行管理。

其中一个关键的后果是分散在未使用的进程地址空间上的内存不能被返回到操作系统用于其他用途。 只有数据段末尾的内存可以返回到操作系统,因此在末尾使用的内存将不得不向下移动到顶端。 实际上几乎没有分配者这样做。 出于这个原因,通常很好地管理一个进程使用的最大内存量,因为这决定了剩余的内存将用于其他进程。