12

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

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

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

澄清

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

4

2 回答 2

6

现代操作系统不允许您直接访问硬件 RAM,而是将其抽象到所谓的虚拟内存中,并按需映射到 RAM。每个进程通常都有自己的完整地址空间的私有副本。这允许操作系统在运行时在 RAM 中移动进程的内存,甚至将其交换到磁盘。这是透明地发生的,即一个进程不会被通知这样的重定位并且不需要有代码来处理这个。(一些实时应用程序可能会使用技术来防止其内存被换出)。

将目标文件链接到可执行文件或动态库时,链接器为函数/方法的 cpu 指令和所有全局变量静态分配内存。当操作系统加载可执行文件或动态库时,它将预先分配的内存映射到实际内存中。

在启动时,每个线程都会收到一个称为堆栈的私有内存区域。每次调用函数/方法时,编译器都会插入代码以自动从堆栈分配(通过递增堆栈指针)足够的内存来保存函数/方法使用的所有参数、局部变量和返回值(如果有)。如果编译器确定将一些变量留在处理器寄存器中就足够了,它不会在堆栈上为其分配内存。当函数/方法返回时,它运行编译器生成的代码以释放(通过递减堆栈指针)该内存。请注意,堆栈上任何对象的析构函数将在它们定义的块退出时被调用,这可能需要很长时间才能返回。此外,编译器可以自由地重用分配的内存,因为它认为合适。

当抛出异常时,编译器会插入特殊代码,该代码知道堆栈的布局,并且可以展开它,直到找到合适的异常处理程序。

与此相反,堆上的内存使用new/分配delete,编译器为此插入代码以使用系统库请求或释放内存。

请注意,这是一个简化的描述,让您了解内存分配的工作原理。

于 2009-08-03T10:50:59.413 回答
5

基本上堆不是由编译器实现的,而是由 C 运行时库实现的。显然,此代码非常依赖于平台。在 Unix 或类 Unix 系统上,实现通常基于 sbrk/brk 系统调用,并分配更大的内存以减少系统调用的数量。然后由堆内存管理器管理此内存。如果需要更多内存,则会发出对 sbrk 的新调用。如果您对调试堆管理例程感兴趣,可以使用 sbrk(0) 获得堆的当前结束地址。大多数内存管理器在进程的生命周期内不将内存返回给操作系统(如果满足某些约束,gnu c 运行时库会这样做)。

http://gee.cs.oswego.edu/dl/html/malloc.html中提供了更详细的描述。

于 2009-08-01T20:11:16.453 回答