内核内存管理:我从哪里开始?

Kernel memory management: where do I begin?

在内核编程方面,我有点菜鸟,想知道是否有人可以为我指出正确的方向,以便在内核设置中开始实施内存管理。我目前正在研究一个玩具内核,并且正在做很多关于这个主题的研究,但我对内存管理这个话题有点困惑。它有很多不同的方面,比如分页和虚拟内存映射。是否有我应该执行的特定命令或任何该做和不该做的事情? 我不是在寻找任何代码或任何东西,我只需要指出正确的方向。任何帮助将不胜感激。

您应该分别考虑多个方面:

  • 管理可用物理内存。
  • 管理内核及其数据结构所需的内存。
  • 管理每个进程的虚拟内存 (space)。
  • 管理任何进程所需的内存,即 mallocfree

为了能够管理任何其他内存需求,您需要知道实际有多少物理内存可用以及其中哪些部分可供您使用。 假设你的内核是由一个多引导兼容的引导加载程序加载的,你会在你从引导加载程序传递的 multiboot header 中找到这个信息(如果我没记错的话,在 x86 上的 eax 中)。 header 包含一个结构,描述哪些内存区域已被使用,哪些可以自由使用。

您还需要以某种方式存储此信息,并跟踪分配和释放的内存。一个简单的方法是维护一个位图,其中位 N 指示从 N * S(N + 1) * S - 1 的(固定大小 S)内存区域是已使用还是空闲。当然,随着内核的进步,您可能希望使用更复杂的方法,例如多级位图或空闲列表,但是上面的简单位图可以帮助您入门。

此内存管理器通常只提供 "large" 大小的内存块,通常是 4KB 的倍数。这对于您习惯于应用程序编程的 mallocfree 风格的动态内存分配当然没有用。

由于动态内存分配将大大简化内核的高级功能(多任务处理、进程间通信等)的实现,因此您通常会专门为内核编写一个内存管理器。它提供了分配 (kalloc) 和释放 (kfree) 任意大小的内存块的方法。此内存来自使用上面的物理内存管理器分配的池。

以上所有内容都发生在内核中。您可能还想为应用程序提供进行动态内存分配的方法。实现这一点在概念上与上面完成的物理内存管理非常相似:

进程只能看到自己的虚拟地址space。它的某些部分对进程不可用(例如内核内存映射到的区域),但大部分将是 "free to use"(也就是说,没有实际的物理内存与之关联)。作为最低限度,内核需要为应用程序提供分配和释放其内存地址 space 的单个页面的方法。分配页面结果(在后台,对应用程序不可见)调用物理内存管理器,以及从请求的页面到这个新分配的内存的映射。

请注意,尽管许多内核为其进程提供对其自身地址的更复杂访问 space 或直接在内核中实现以下某些任务。

能够像以前一样分配和释放页面(4KB 大部分)对动态内存管理没有帮助,但和以前一样,这通常由使用这些大内存块的其他一些内存管理器处理作为池为应用程序提供更小的块。一个突出的例子是 Doug Lea's allocator。像这样的内存管理器通常作为链接到每个应用程序的库(很可能是标准库的一部分)实现。