Dan*_*ker 5 heap stack operating-system virtual-memory
我正在写一个内核和需求(并希望)把多个栈和堆到虚拟内存,但我无法弄清楚如何有效地把它们.普通程序如何做到这一点?
堆栈和堆是如何(或在哪里)放入32位系统提供的有限虚拟内存中,以便它们具有尽可能多的增长空间?
例如,当一个简单的程序加载到内存中时,其地址空间的布局可能如下所示:
[ Code Data BSS Heap-> ... <-Stack ]
Run Code Online (Sandbox Code Playgroud)
在这种情况下,堆能够增长大如虚拟内存允许(如到堆栈),我相信这是堆是如何工作的大多数程序.没有预定义的上限.
许多程序都将共享库放在虚拟地址空间中的某个位置.然后有多线程程序,有多个堆栈,每个线程一个..NET程序有多个堆,所有这些都必须能够以这种或那种方式增长.
我只是没有看到如何在没有对所有堆和堆栈的大小预先设定的限制的情况下合理有效地完成这项工作.
简而言之,由于您的系统资源始终是有限的,因此您不可能无限。
内存管理始终由多个层组成,每个层都有明确定义的职责。从程序的角度来看,应用程序级管理器是可见的,通常只关心它自己的单个分配的堆。如果需要,上面的级别可以处理从一个全局堆中创建多个堆并将它们分配给子程序(每个子程序都有自己的内存管理器)。上面可能是它使用的标准malloc()/ free(),上面是操作系统处理页面和每个进程的实际内存分配(它基本上不仅不关心多个堆,而且一般也不关心用户级堆)。
内存管理的成本很高,陷入内核的成本也很高。将两者结合起来可能会严重影响性能,因此从应用程序的角度来看,实际的堆管理实际上是在用户空间(C 运行时库)中实现的,以提高性能(以及目前超出范围的其他原因) )。
当加载共享(DLL)库时,如果在程序启动时加载它,它当然很可能会加载到 CODE/DATA/等,因此不会发生堆碎片。另一方面,如果它是在运行时加载的,那么除了耗尽堆空间之外几乎没有其他机会。当然,静态库只是简单地链接到 CODE/DATA/BSS/etc 部分。
最终,您需要对堆和堆栈施加限制,以便它们不太可能溢出,但您可以分配其他堆和堆栈。如果一个人需要超越这一限制,你可以
free()通常表现不佳的原因。考虑到平均每个堆栈帧相当大,1KB call(如果应用程序开发人员缺乏经验,可能会发生),10MB 堆栈足以容纳 10240 个嵌套call-s。顺便说一句,除此之外,每个线程几乎不需要多个堆栈和堆。