3

可能的重复:
堆和堆栈内存是如何管理、实现和分配的?
C++ 中的栈、静态和堆

在 C/C++ 中,我们可以将变量、函数、成员函数、类的实例存储在堆栈或堆上。

每个是如何实现的?它是如何管理的(高级)?gcc 是否预先分配一块内存用于堆栈和堆,然后根据请求分配?原始内存是否来自 RAM?

可以在堆而不是堆栈上分配函数吗?

             --Clarification--

我真的在问堆和堆栈内存的实现和管理。阅读参考问题后,我没有找到任何可以解决的问题...感谢链接

4

1 回答 1

13

我认为对于您的问题,至少可以轻松地为操作系统这本书写一些章节。我建议您阅读 Tanenbaum:现代操作系统。

堆和堆栈的主要区别,一个是每个进程项,另一个是每个线程项。最初,当程序启动时,它会获得一些最小的堆和一些堆栈段。堆增长,堆栈是静态的(对于每个线程)。如果您编写一个不终止的递归函数(无限递归),您将得到堆栈溢出;)任何函数调用在堆栈段上都有一个堆栈帧,当函数离开时,堆栈被展开并且框架可以被自由使用下一个功能。栈是一个连续的线性结构。在 Linux 上,您可以通过环境变量配置进程的堆栈段大小。在 Windows 上(至少使用 MS Visual C++),您可以传递带有堆栈段大小的链接器标志。在编译时分配一些大数组时也可能产生堆栈溢出:

char test[1000000];

堆是一个不同的故事。当一个进程启动时,堆大小是一些默认值,并且可以从操作系统到操作系统或在该操作系统上使用的配置(例如,在 Windows 上默认为 2MB,据我记得)。此外,如果您需要更多堆,为变量分配更多空间等,它会增长。如果程序没有释放堆内存,它就会耗尽它(或堆空间)。堆实现有不同的数据结构,其中一些是二叉树的衍生物,一些不是例如斐波那契堆(树的森林)。您可以阅读一些关于如何编写内存分配器的文章等。必须优化这些数据结构,以便在需要释放分配的块时查找堆节点,或者在需要新的堆空间时追加(查找空闲块)。

32 位操作系统上的每个进程都有 4GB 的虚拟地址空间。正如您可以想象的那样,不可能有那么多 RAM 适合所有具有 4GB 虚拟地址空间的进程。操作系统内存按页面组织,当不再需要或过期时,这些页面将被交换到 HD。这就是分页发挥作用的地方。一切都映射到页面:具有堆栈或不断增长的堆的进程。由于堆的结构是动态增长的,它可以放在多个页面上。这就是为什么堆访问可能非常昂贵的原因,因为如果页面不在内存中,则会发生页面错误,并且操作系统必须从磁盘加载页面(这可能会慢很多)。正在执行的线程的堆栈帧在处理器缓存中,这比 RAM 快得多。

可能有不同的堆类型,可能有对小对象非常快的堆或在多线程环境中非常有效的堆。Alexandrescu 在“现代 C++ 设计”中描述了如何开发小对象分配器和管理小对象的堆。此实现在他的 Loki C++ 库中可用。一些嵌入式系统提供物理上不同的内存区域,可以在其中实现不同的堆类型。如果您想击败编译器,编写自己的分配器(堆管理器等)是一项艰巨的工作。

问候,
欧文斯

于 2009-07-31T15:44:01.630 回答