【问题标题】:Stack Memory vs Heap Memory [duplicate]堆栈内存与堆内存[重复]
【发布时间】:2011-08-15 17:33:04
【问题描述】:

可能重复:
What and where are the stack and heap

我正在使用 C++ 编程,我一直想知道堆栈内存与堆内存到底是什么。我所知道的是,当我调用 new 时,我会从堆中获取内存。如果如果创建局部变量,我会从堆栈中获取内存。在互联网上进行了一些研究后,最常见的答案是堆栈内存是临时的,而堆内存是永久的。

堆栈和堆内存模型是操作系统还是计算机体系结构的概念?那么其中一些可能不遵循堆栈和堆内存模型,或者它们都遵循它?

堆栈和堆内存是对虚拟内存的内存模型的抽象(可能在磁盘和 RAM 之间交换内存)。那么堆栈和堆内存在物理上可能是 RAM 还是磁盘?那么堆分配似乎比堆栈分配慢的原因是什么?

另外,主程序是在栈还是堆中运行?

另外,如果进程用完分配的堆栈内存或堆内存会怎样?

谢谢

【问题讨论】:

  • @meagar 这确实引发了您链接到的问题中未提及的一些问题。

标签: c++ memory


【解决方案1】:

在 C++ 中,堆栈内存是存储/构造局部变量的地方。堆栈还用于保存传递给函数的参数。

堆栈与 std::stack 类非常相似:您将参数压入它,然后调用一个函数。然后该函数知道它期望的参数可以在堆栈的末尾找到。同样,该函数可以将局部变量压入堆栈并在从函数返回之前将它们从堆栈中弹出。 (警告 - 编译器优化和调用约定都意味着事情并非如此简单)

最好从底层理解堆栈,我推荐Art of Assembly - Passing Parameters on the Stack。很少,如果有的话,您会考虑使用 C++ 进行任何类型的手动堆栈操作。

一般来说,堆栈是首选,因为它通常位于 CPU 缓存中,因此涉及存储在其上的对象的操作往往更快。然而,堆栈是一种有限的资源,不应该用于任何大的东西。堆栈内存耗尽称为Stack buffer overflow。这是一件很严肃的事情,但除非你有一个疯狂的递归函数或类似的东西,否则你真的不应该遇到它。

堆内存就像 rskar 所说的那样。通常,使用 new 分配的 C++ 对象或使用 malloc 之类分配的内存块最终会在堆上。堆内存几乎总是必须手动释放,尽管您应该真正使用智能指针类或类似的类以避免需要记住这样做。堆内存不足可能(会?)导致 std::bad_alloc。

【讨论】:

  • "堆栈内存几乎总是必须手动释放。"你的意思是堆内存。另外,值得一提的是,堆内存是“全局的”,当你用完堆时,其他应用程序也会用完堆。不过,堆栈具有本地范围。
【解决方案2】:

堆栈内存具体是指可通过 CPU 的堆栈寄存器访问的内存范围。堆栈被用作在汇编语言中实现“跳转子程序”-“返回”代码模式的一种方式,也被用作实现硬件级中断处理的一种手段。例如,在中断期间,堆栈用于存储各种 CPU 寄存器,包括状态(指示操作的结果)和程序计数器(中断发生时程序中的 CPU 在哪里)。

堆栈内存在很大程度上是通常 CPU 设计的结果。它的分配/释放速度很快,因为它是严格的后进先出设计。这是对堆栈寄存器的移动操作和递减/递增操作的简单问题。

堆内存只是程序加载并分配堆栈内存后剩余的内存。它可能(或可能不)包括全局变量空间(这是约定问题)。

具有虚拟内存和内存映射设备的现代抢先式多任务操作系统使实际情况更加复杂,但简而言之就是堆栈与堆。

【讨论】:

  • 这在很多方面都是错误的。在我知道的任何架构上,“堆栈内存”和“堆内存”之间通常没有区别。两者都可以通过堆栈指针、索引寄存器或其他方式访问。堆栈指针和索引寄存器都可以任意更改以访问进程可用的任何内存。
  • @unapersson:内存就是内存,当然可以更改和分配SP。 “堆栈内存”更多地是一个意图或角色的术语 - 不一定是专门的硬件。顺便说一句,在 6502 的情况下,您的堆栈确实卡在第 1 页(字节 256 到 511)。
  • @rskar 确实如此。早在 1984 年,我就编写了 KERMIT 协议的实现,在 BBC Micro 上使用 6502 汇编程序(对于 Z80 程序员来说不是一个愉快的经历)进行了完整的 VT100 终端仿真,所以我知道我在这里说什么。
  • @rskar 对于大多数架构来说,栈内存和普通内存没有区别。即使在 6502 上,您也可以(有时必须)在“普通”内存中实现自己的堆栈——您只是无法通过调用和返回操作码来使用它。即使在 6502 上,堆栈内存也没有什么特别之处,只是关于它是如何访问的(通过 6502 堆栈页面)您似乎在暗示堆栈和其他类型的内存之间实际上存在物理差异。
  • @unapersson:我很抱歉 - 我从来没有暗示堆栈和其他类型的内存之间实际上存在物理差异。
【解决方案3】:

这是一种语言抽象——有些语言两者兼有,有些语言两者兼有。

在 C++ 的情况下,代码不在堆栈或堆中运行。您可以通过重复调用new 在循环中分配内存而不调用delete 来释放它来测试如果堆内存用完会发生什么。 但在此之前请先备份系统

【讨论】:

  • “在尝试填充堆之前进行系统备份”?你在哪个平台上,MS-DOS?
  • @larsman 但是您是否取消了对用户进程的限制?你有没有试过,比如说,Windows?对于我们大多数 Unix 人来说,“重启的必要性”是被解雇的下一步。
  • @unapersson:所有系统(Linux、Mac OS X、OpenBSD)都有默认限制。不,我从不在 Windows 上尝试任何重物,我讨厌清理碎玻璃;)
  • @unapersson:啊,对。我没有在生产服务器上运行此类测试的习惯,我相信我的本地计算中心不会取消对 HPC 集群的限制:)
  • @TonyK 那将是真实的世界(出现问题,如果出现问题,你必须付出代价),而不是你生活的快乐的世界,我猜。
猜你喜欢
  • 2011-05-28
  • 2011-03-29
  • 2012-09-23
  • 2020-04-24
  • 2012-04-12
  • 2023-03-03
  • 1970-01-01
相关资源
最近更新 更多