我正在编写一个内核并且需要(并且想要)将多个堆栈和堆放入虚拟内存中,但是我不知道如何有效地放置它们。普通程序是如何做到的?
堆栈和堆如何(或在哪里)放置到 32 位系统提供的有限虚拟内存中,以便它们具有尽可能多的增长空间?
例如,当一个简单的程序被加载到内存中时,其地址空间的布局可能如下所示:
[ Code Data BSS Heap-> ... <-Stack ]
在这种情况下,堆可以增长到虚拟内存允许的大小(例如,直到堆栈),我相信这就是堆对大多数程序的工作方式。没有预定义的上限。
许多程序都有共享库,这些库位于虚拟地址空间的某个位置。
然后是具有多个堆栈的多线程程序,每个线程一个。 .NET 程序有 multiple heaps ,所有这些都必须能够以一种或另一种方式发展。
如果不对所有堆和堆栈的大小设置预定义的限制,我只是看不出这是如何合理有效地完成的。
最佳答案
我假设您已经完成了内核中的基础知识,一个用于页面错误的陷阱处理程序,可以将虚拟内存页面映射到 RAM。下一个级别,您需要一个虚拟内存地址空间管理器,用户模式代码可以从中请求地址空间。选择一个防止过度碎片化的段粒度,64KB(16 页)是一个不错的数字。允许用户模式代码保留空间和提交空间。一个 4GB/64KB = 64K x 2 位的简单位图用于跟踪段状态即可完成工作。页错误陷阱处理程序还需要查阅此位图以了解页请求是否有效。
堆栈是固定大小的 VM 分配,通常为 1 兆字节。一个线程通常只需要其中的几页,具体取决于函数嵌套级别,因此保留 1MB 并仅提交前几页。当线程嵌套得更深时,它会触发一个页面错误,内核可以简单地将额外的页面映射到 RAM 以允许线程继续运行。您需要将底部的几页标记为特殊页面,当线程页面错误时,您可以声明该网站的名称。
堆管理器最重要的工作是防止碎片化。最好的方法是创建一个后备列表,按大小对堆请求进行分区。小于 8 个字节的所有内容都来自第一个段列表。从第二个到 8 到 16,从第三个到 16 到 32,等等。随着你的上升,增加桶的大小。您必须调整铲斗尺寸以获得最佳平衡。非常大的分配直接来自 VM 地址管理器。
第一次命中后备列表中的条目时,您分配一个新的 VM 段。您可以使用链表将该段分割为更小的块。当这种分配被释放时,您将该块添加到空闲块列表中。无论程序请求如何,所有块都具有相同的大小,因此不会有任何碎片。当该段被完全使用并且没有空闲块可用时,您分配一个新段。当一个段只包含空闲块时,您可以将它返回给 VM 管理器。
此方案允许您创建任意数量的堆栈和堆。
关于operating-system - 多个堆栈和堆放在虚拟内存中的什么位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16155690/