【发布时间】:2010-11-03 02:27:55
【问题描述】:
我在思考 Linux 内核是如何实现系统调用的,我想知道是否有人可以给我一个关于 sbrk/brk 工作原理的高级视图?
我已经查看了内核代码,但是代码太多了,我不明白。我希望有人提供摘要?
【问题讨论】:
标签: linux system-calls sbrk brk
我在思考 Linux 内核是如何实现系统调用的,我想知道是否有人可以给我一个关于 sbrk/brk 工作原理的高级视图?
我已经查看了内核代码,但是代码太多了,我不明白。我希望有人提供摘要?
【问题讨论】:
标签: linux system-calls sbrk brk
好吧,从超高层的角度来看,内核分配一个可分页的内存块,修改请求该块的进程的页表,以便将内存映射到进程的 VA 空间,然后返回地址。
【讨论】:
Linux 内核如何将内存传递给用户进程的一个关键概念是,可用的进程堆(数据段)从底部向上增长。内核不跟踪单个内存块,只跟踪一个连续的内存块。 brk/sbrk 系统调用扩展了进程拥有的内存量,但由进程来管理它的可用部分。
这样做的一个关键结果是,分散在进程地址空间中的未使用的内存无法返回给操作系统用于其他用途。只有数据段末尾的内存可以返回给操作系统,因此末尾附近的正在使用的内存必须向下移动到顶部。实际上,几乎没有分配器这样做。出于这个原因,管理一个进程使用的最大内存量通常很重要,因为这决定了为其他进程留下多少内存。
【讨论】:
您必须了解虚拟内存的工作原理,以及 MMU 映射与真实 RAM 的关系。
真正的 RAM 被划分为页面,传统上每个页面为 4kB。每个进程都有自己的 MMU 映射,它为该进程提供一个线性内存空间(在 32 位 linux 中为 4GB)。当然,并不是所有的都被实际分配。起初,它几乎是空的,即没有与大多数地址关联的真实页面。
当进程遇到未分配的地址(试图读取、写入或执行它)时,MMU 会产生故障(类似于中断),并调用 VM 系统。如果它决定应该有一些 RAM,它会选择一个未使用的 RAM 页并与该地址范围相关联。
这样,内核不关心进程如何使用内存,进程也不关心有多少 RAM,它总是有相同的线性 4GB 地址空间。
现在,brk/sbrk 工作在稍高的水平:原则上,任何“超出”该标记的内存地址都是无效的,并且如果被访问则不会获得 RAM 页,而是会终止进程。用户空间库在此限制内管理内存分配,并且仅在需要时请求内核增加它。
但是,即使进程通过将brk 设置为允许的最大值来启动,它也不会分配真正的 RAM 页面,直到它开始访问所有内存地址。
【讨论】:
在一个非常高级的视图中,Linux 内核将进程可见的内存跟踪为几个“内存区域”(struct vm_area_struct)。还有一个结构表示(再次在非常高级的视图中)进程的整个地址空间(struct mm_struct)。每个进程(除了一些内核线程)只有一个struct mm_struct,它又指向它可以访问的所有struct vm_area_struct。
sys_brk 系统调用(在mm/mmap.c 中找到)只是调整其中一些内存区域。 (sbrk 是 brk 的 glibc 包装器)。它通过比较brk 地址的旧值(在struct mm_struct 中找到)和请求的值来实现。
首先查看mmap 系列函数会更简单,因为brk 是它的一个特例。
【讨论】: