堆和堆栈内存是如何管理、实现和分配的?

Posted

技术标签:

【中文标题】堆和堆栈内存是如何管理、实现和分配的?【英文标题】:How is heap and stack memories managed, implemented, allocated? 【发布时间】:2010-11-15 19:34:33 【问题描述】:

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

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

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

澄清

我真的在问堆和堆栈内存的实现和管理。 After reading referenced question,我没有找到任何可以解决...感谢链接

【问题讨论】:

欺骗***.com/questions/408670/stack-static-and-heap-in-c 等等 好吧,再想一想,情况就不同了,因为我真的在问堆和堆栈内存的实现和管理。阅读参考问题后,我没有找到任何可以解决的问题...感谢您提供的链接... @ultraman:如果不同,请重写以强调差异。不要评论你的问题。是你的。重写它以获得你真正想要的信息。 我不太喜欢结束问题,但这对我来说是一样的。改写为足够不同,我可能会收回我的投票。 @S.Lott 我将重写主题,但我已经在问题中问了我想要什么.. 正是:) 【参考方案1】:

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

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

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

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

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

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

【讨论】:

【参考方案2】:

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

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

【讨论】:

并非总是如此。在功能足够强大的操作系统上,CRT 不必这样做。与堆栈类似:如果操作系统足够强大,编译器就不必做那么多。操作系统可以处理堆栈但不能处理堆的情况很常见,但并不普遍。 我确信 MSVC 会尽可能将大部分内存返回给操作系统。

以上是关于堆和堆栈内存是如何管理、实现和分配的?的主要内容,如果未能解决你的问题,请参考以下文章

iOS堆栈内存区别

理解JavaScript中的堆和栈

c++堆栈的各自大小,堆和栈的各自定义

java 堆栈内存分析详解

java中啥是堆和栈,如何应用,最好举个例子,并详细地说明一下,谢谢了

变量存储区:堆和栈