堆栈与堆栈和堆与堆

Posted

技术标签:

【中文标题】堆栈与堆栈和堆与堆【英文标题】:a stack vs the stack and a heap vs the heap 【发布时间】:2014-06-23 15:21:34 【问题描述】:

我正在为我的数据组织决赛而学习,并且我正在检查堆栈和堆,因为我知道它们将进入决赛并且我需要知道它们之间的差异。 我知道 Stack 是什么,Heap 是什么。

但我对什么是堆栈和什么是堆感到困惑。

堆栈是RAM中存储内存的地方,如果空间不足,就会发生堆栈溢出。对象默认存储在这里,当对象超出范围时会重新分配内存,速度更快。

堆是RAM中存储内存的地方,如果空间不足,操作系统会分配更多。对于要存储在堆上的对象,需要使用 new 运算符告诉它,并且只有在被告知时才会被释放。可能会出现碎片问题,它比堆栈慢,并且它可以更好地处理大量内存。

但是什么是栈,什么是堆呢?它是记忆的存储方式吗?比如静态数组或者静态向量是栈类型,动态数组,链表是堆类型?

谢谢大家!

【问题讨论】:

I know what the Stack is and what the Heap is, but I'm confused on what a stack is and what a heap is. 嗯? “堆栈”和“堆”是通用概念。在基于 C 的语言中,“堆栈”和“堆”是特定的实体——“堆栈”是管理调用/返回、自动变量存储等的“执行堆栈”,而“堆”是您mallocnew 存储件。可以有其他(用户定义的)堆栈和堆来管理完全不同的任务。 见en.wikipedia.org/wiki/Stack_%28abstract_data_type%29和en.wikipedia.org/wiki/Heap_%28data_structure%29 不要将Abstract Data Types (ADTs) 与特定语言的特定实现概念(与 ADT 不严格相关)混淆。 ..当然,Google 上没有这些信息。 【参考方案1】:

“堆栈”和“堆”是程序或操作系统以特定方式使用的内存块。例如,the call stack 可以保存与函数调用有关的数据,the heap 是专门用于动态分配空间的内存区域。

将这些与堆栈和堆进行对比data structures

stack 可以被认为是一个数组,其中最后一个元素将是第一个元素。对此的操作称为 push 和 pop。

heap 是一种数据结构,表示一种特殊类型的图,其中每个节点的值都大于节点子节点的值。

附带说明,请记住,“堆栈”或“堆”或任何堆栈/堆数据结构对于任何给定的编程语言都是独一无二的,但只是计算机科学领域的概念。

【讨论】:

这是通用术语“堆”的具体用法。可以有一个文件句柄“堆”,例如,不作为图形进行管理。 @HotLicks - 此时我们将根据字典定义,而不是计算机科学定义。 所以你会声称使用术语“堆”来表示图的唯一例外是 C/C++/Java 堆??? 也许我应该更具体一点:在计算机科学的上下文中,“堆”是一种满足堆属性的树型数据结构(其中每个节点的值都小于其父值)。将计算机科学中的任何其他东西称为“堆”会产生误导。例如,文件句柄集合不是堆,因为它 1) 不是树结构,并且 2) 不满足堆属性。 @HotLicks - 正确,这也是为什么最好将其称为“内存池”或类似名称的原因。 :P【参考方案2】:

我不会进入虚拟内存(如果需要,请阅读相关内容)所以让我们简化并假设您有一定大小的 RAM。

您的代码包含静态初始化数据和一些静态未初始化数据(C++ 中的静态意味着像全局变量)。你有你的代码。

当您编译某些东西时,编译器(和链接器)会按以下方式组织并将您的代码转换为机器代码(字节码、1 和 0):

二进制文件(和目标文件)被组织成段(RAM 的部分)。

首先你有 DATA 段。这是包含初始化变量值的段。因此,如果您有变量,即int a=3, b = 4,它们将进入数据段(4 字节的 RAM 包含 00000003h,其他 4 字节包含 000000004h,十六进制表示法)。它们是连续存储的。

那么你就有了代码段。您的所有代码都被翻译成机器代码(1 和 0)并连续存储在该段中。

那么您就有了BSS 段。有未初始化的全局变量(所有未初始化的静态变量)。

那么您就有了STACK 段。这是为堆栈保留的。默认情况下,堆栈大小由操作系统确定。你可以改变这个值,但我现在不会进入这个。所有局部变量都放在这里。当你调用某个函数时,首先将func args压入堆栈,然后返回地址(退出函数时返回的地址),然后将一些计算机寄存器压入此处,最后函数中声明的所有局部变量都得到保留堆栈空间

你有 HEAP 段。这是使用运算符 new 存储对象和数据的 RAM 的一部分(大小也由操作系统决定)。

然后所有的段一个接一个地堆放 DATA, CODE, BSS, STACK, HEAP。还有一些其他的段,但这里不感兴趣,它们由操作系统加载到 RAM 中。二进制文件还有一些头文件,其中包含您的代码从哪个位置(内存中的地址)开始的信息。

简而言之,它们都是 RAM 的一部分,因为正在执行的所有内容都加载到 RAM 中(不能在 ROM(只读)中,也不能在 HDD 中,因为 HDD 仅用于存储文件。

【讨论】:

什么?你的意思是我不允许在ROM中执行代码?哦亲爱的。我将不得不放弃很多工作并重新开始。 不,您从 ROM 执行代码,但 ROM 用于在您启动计算机时执行代码。您按下 POWER 按钮,comp 打开,开始从固定地址读取(该地址是某个 ROM 地址)。有一个小代码可以执行以下操作:将一些代码从 ROM 复制到 RAM,继续执行从 RAM 复制的代码,做一些事情,查看 HDD 的引导扇区并将 OS 引导文件复制到 RAM,执行它并启动 OS。之后就不需要执行ROM了,双击某个文件运行,loader加载到ROM中执行。 我的意思是您的答案不准确(它说“正在执行的所有内容都加载到 RAM 中)不正确。您的答案也非常特定于一种机器架构(诚然是一种常见的架构)并提供了大量细节,但并未真正解决您所回答的问题。 是的,我的意思是不能加载到 ROM 中。 :) 那里有细节,所以这个人可以理解更大的图景。其他人告诉他堆栈和堆是什么,我解释了背景(简化)。【参考方案3】:

当专门提到 C++ 的内存模型时,堆和堆栈指的是内存区域。这很容易与栈数据结构和堆数据结构混淆。但是,它们是不同的概念。

在讨论编程语言时,堆栈内存被称为“堆栈”,因为它的行为类似于堆栈数据结构。堆有点用词不当,因为它不一定(或可能)使用堆数据结构。请参阅Why are two different concepts both called "heap"?,了解为什么 C++ 的堆和数据结构的名称是相同的,尽管它们是两个不同的概念。

所以要回答你的问题,这取决于上下文。在编程语言和内存管理的上下文中,堆和堆栈是指具有特定属性的内存区域。否则,它们会引用特定的数据结构。

【讨论】:

【参考方案4】:

“堆栈”的技术定义是一种后进先出 (LIFO) 数据结构,其中数据被推入和拉出顶部。就像现实世界中的一堆盘子一样,你不会从中间或底部拉出一个,你[通常]不会从数据结构堆栈的中间或底部拉出数据。当有人在编程方面谈论 堆栈时,它通常(但不总是)意味着硬件堆栈,它由 CPU 中的堆栈指针寄存器控制。

就“堆”而言,就每个人都可以同意的定义而言,这通常会变得更加模糊。最好的定义可能是“为动态内存管理分配空间的大量空闲内存”。换句话说,当您需要新内存时,无论是用于数组还是使用 new 运算符创建的对象,它都来自操作系统为您的程序保留的堆。这是来自程序 POV 的“堆”,但只是来自操作系统 POV 的“堆”。

【讨论】:

“堆”可能是类似对象的集合,而不仅仅是空闲存储块。 没错,但这不是 OP 工作的环境。将 OP 的“堆”称为“内存堆”可能更有意义。【参考方案5】:

关于堆栈,您需要了解的重要一点是堆栈与函数/方法调用之间的关系。每个函数调用都会在堆栈上保留空间,称为堆栈帧。该空间包含您的自动变量(在函数体内声明的变量)。当您退出该函数时,堆栈帧及其包含的所有自动变量都会消失。

这种机制在使用 CPU 资源方面非常便宜,但是这些堆栈分配的变量的生命周期显然受到函数范围的限制。

另一方面,堆上的内存分配(对象)可以“永远”存在,或者只要您需要它们,就可以不考虑程序的控制流。不利的一面是,由于您没有自动管理这些堆分配的对象的生命周期,因此您必须 1) 自己管理生命周期,或者 2) 使用诸如智能指针之类的特殊机制来管理这些对象的生命周期。如果您弄错了,您的程序就会出现内存泄漏,或者访问的数据可能会意外更改。

Re:关于堆栈与堆栈的问题:当您使用多个线程时,每个线程都有一个单独的堆栈,以便每个线程可以独立地流入和流出函数/方法。大多数单线程程序只有一个堆栈:常用术语中的“堆栈”。

对于堆也是如此。如果您有特殊需要,可以分配多个堆并在分配时选择应该使用哪个堆。这不太常见(而且比我在这里提到的要复杂得多。)

【讨论】:

以上是关于堆栈与堆栈和堆与堆的主要内容,如果未能解决你的问题,请参考以下文章

堆栈和队列

堆与堆栈分配的含义(.NET)

java堆栈堆栈的区别

用例子解释编程中的栈溢出和堆溢出? [复制]

关于JAVA堆栈的简单说明

Java中的堆和栈以及堆栈的区别