我在考虑Linux内核如何实现系统调用,我想知道是否有人可以给我一个关于sbrk / brk如何工作的高级视图?
我已经查看了内核代码,但是它有很多内容而且我不理解它。我希望得到某人的摘要?
答案 0 :(得分:23)
在一个非常高级别的视图中,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
是它的一个特例。
答案 1 :(得分:18)
您必须了解虚拟内存的工作原理,以及MMU映射与实际RAM的关系。
真正的RAM分为页面,传统上每个4kB。每个进程都有自己的MMU映射,它为该进程提供了一个线性内存空间(32位linux中为4GB)。当然,并非所有这些都是实际分配的。起初,它几乎是空的,也就是没有真正的页面与大多数地址相关联。
当进程遇到未分配的地址(尝试读取,写入或执行它)时,MMU会生成错误(类似于中断),并调用VM系统。如果它决定某些RAM应该在那里,它会选择一个未使用的RAM页面并与该地址范围相关联。
这样,内核不关心进程如何使用内存,而且进程并不关心有多少RAM,它总是具有相同的线性4GB地址空间。
现在,brk/sbrk
的工作水平稍高一些:原则上任何超出该标记的内存地址都是无效的,如果访问则不会获得RAM页面,该过程将被杀死。用户空间库管理此限制内的内存分配,并且仅在需要时请求内核增加它。
但即使通过将brk
设置为允许的最大值来启动进程,在开始访问所有内存地址之前,它也不会获得真正的RAM页面。
答案 2 :(得分:4)
好吧,从超高级别的角度来看,内核会分配一个可分页的内存块,修改请求该块的进程的页表,以便将内存映射到进程的VA空间,然后返回地址。 / p>
答案 3 :(得分:2)
Linux内核如何将内存传递给用户进程的关键概念是可用堆进程(数据段)从底部开始增长。内核不跟踪单个内存块,只跟踪连续的内存块。 brk / sbrk系统调用会扩展进程所拥有的内存量,但是由可用部分管理它的过程决定了。
这样做的一个关键结果是,分散在未使用的进程地址空间中的内存无法返回到操作系统以供其他用途。只有数据段最末端的内存才能返回给操作系统,因此靠近末端的使用中的内存必须向下移动到顶部。实际上,几乎没有分配器可以做到这一点出于这个原因,通常很重要的是要很好地管理进程使用的最大内存量,因为这决定了为其他进程留下多少内存。