operating-system - 多个堆栈和堆放在虚拟内存中的什么位置?

标签 operating-system heap-memory virtual-memory stack-memory

我正在编写一个内核并且需要(并且想要)将多个堆栈和堆放入虚拟内存中,但是我不知道如何有效地放置它们。普通程序是如何做到的?

堆栈和堆如何(或在哪里)放置到 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/

相关文章:

linux - 如何检查linux为jvm分配的堆大小

memory-management - 如果我们有无限内存,那么我们还需要分页吗?

c++ - 虚拟内存和对齐——它们如何结合在一起?

iOS:工具、分配达到峰值至持平线

c - 对操作系统内核链接的 undefined reference

java - 操作系统如何决定如何运行 .exe

c++ - 是否可以使用线程来加快文件读取速度?

.net - C# 中的 GetWriteWatch()?

operating-system - 如果没有分页概念,虚拟内存还能存在吗?

java - 我的 Glassfish 设置是否泄漏内存?