- 什么是堆叠和堆叠?
- 他们在电脑记忆中身处何方?
- 它们在多大程度上受到操作系统或语言运行时间的控制?
- 其范围是什么?
- 是什么决定了它们的大小?
- 是什么让一个更快?
当前回答
许多答案作为概念是正确的,但我们必须指出,硬件(即微处理器)需要堆叠,才能调用子程序(集合语言的CALL)。 (OOP的家伙会称之为它)。方法)
在堆叠上,您保存返回地址, 并呼叫 push / ret pop 由硬件直接管理 。
您可以使用堆栈来设定通过参数. 即使比使用登记册要慢( 微处理器大师会说, 还是一本好的 1980s BIOS 书...) 。
- 没有堆叠无 无微处理器可以工作。 (我们无法想象一个程序, 即使是以组装语言, 没有子例程/功能)
- (一个集会语言方案可以工作,因为这个语言方案是一个OS概念,作为cloc,即OS/Lib呼叫。)
堆叠使用速度更快, 如下:
- 硬件,甚至推/棒子都是非常有效的。
- 商场需要进入内核模式,使用锁/气压(或其他同步原始物),执行一些代码,并管理一些跟踪分配情况所需的结构。
其他回答
堆叠是作为执行线索的抓抓空间预留的内存。 当调用函数时, 在堆叠顶部保留一个区块, 用于本地变量和一些簿记数据。 当该函数返回时, 块会被未使用, 下次调用函数时可以使用。 堆叠总是保留在 LIFO 的顺序中( 最后一个在第一个出处) ; 最近保留的区块总是要解开的下一个区块 。 这样可以非常简单地跟踪堆叠; 从堆叠中释放一个区块只不过是调整一个指针而已 。
堆积是用于动态分配的内存。 与堆叠不同, 堆积区块的分配和分配没有强制模式; 您可以随时分配块块, 并随时释放它。 这就使得追踪堆积中哪些部分在任何特定时间分配或自由使用变得更加复杂; 许多定制的堆积分配器可以调和不同使用模式的堆积性能 。
每一串线索都有堆叠, 而通常应用程序只有一堆(尽管不同类型分配的多堆线索并不罕见) 。
直接回答你的问题:
它们在多大程度上受到操作系统或语言运行时间的控制?
当线索创建时, OS 会为每个系统级线索分配书架。 通常情况下, OS 会被语言运行时间调用来分配应用程序的堆积 。
其范围是什么?
堆栈附在线条上, 所以当线条退出时, 堆栈会被回收。 堆栈通常在运行时在应用程序启动时分配, 当应用程序( 技术处理) 退出时再回收 。
是什么决定了每个孩子的大小?
当创建线条时,会设定堆叠的大小。 程序启动时会设定堆积的大小, 但随着空间需要, 可能会增长( 分配器要求操作系统的内存更多 ) 。
是什么让一个更快?
堆叠速度更快, 因为访问模式使得从堆叠中分配和处理内存变得微不足道( 指针/ 内插器仅仅是递增或衰减) , 而堆叠在分配或交易地点的簿记上复杂得多 。 此外, 堆叠中的每个字节往往会非常频繁地被再利用, 这意味着它往往被映射到处理器的缓存处, 使其速度非常快 。 堆积的另一个性能冲击是, 堆积( 大多是一个全球资源) , 通常必须是多读的安全性, 也就是说, 每一个分配和交易地点需要 — 通常 — 与程序中的“ 所有” 其它堆积权限同步 。
明确表明:
图像来源 :vikashazrati.wordpress.com 译者注:
其他答案只是避免解释静态分配意味着什么。 因此,我将解释三种主要分配形式,以及它们通常与下面的堆积、堆叠和数据段的关系。 我还将在C/C++和Python中展示一些例子,以帮助人们理解。
“ 静态” (AKA静态分配) 变量没有在堆叠上分配 。 不要假设- 许多人这样做, 只是因为“ 静态” 听起来像“ 堆叠 ” 。 它们实际上既不存在于堆叠中,也不存在于堆叠中。 它们属于所谓的“ 堆叠” 的一部分 。数据元数据段.
然而,一般而言最好考虑 " 。范围范围" 和 "寿命寿命而不是"堆"和"堆"
范围指代码中哪些部分可以访问变量。本地范围(只能由当前函数访问)和全球范围尽管范围可能变得更加复杂,但范围(无论何处都可以进入)仍会变得更加复杂。
寿命指变量在程序执行期间分配和交易的时间。通常我们想到的是静静分配(在程序的整个整个期间,将始终可变,因此有助于在多个函数调用中储存相同信息)相对于自动分配(只有在对函数的单一次呼叫中,可变性才能持续,使该函数可用于存储仅在您函数期间使用、一旦完成即可丢弃的信息)和动态分配(期限在运行时界定的可变数据,而不是静态或自动的时间。)
尽管大多数编译者和口译员在使用堆叠、堆肥等方面也采取了类似的做法,但只要行为正确,编译者有时会打破这些公约。例如,由于优化,本地变量可能只存在于一个登记册中,或者完全删除,即使大多数本地变量存在于堆叠中。正如在几个评论中指出的,您可以自由使用一个甚至不使用堆叠或堆积的编译者,而是使用其他一些存储机制(因为堆叠和堆积对这很重要,因为堆叠和堆积对这很重要 ) 。
我将提供一个简单的附加注释的 C 代码来说明所有这一切。 最好的学习方法是在调试器下运行一个程序并观看行为。 如果您喜欢阅读 Python, 请跳到答案的结尾 :
// Statically allocated in the data segment when the program/DLL is first loaded
// Deallocated when the program/DLL exits
// scope - can be accessed from anywhere in the code
int someGlobalVariable;
// Statically allocated in the data segment when the program is first loaded
// Deallocated when the program/DLL exits
// scope - can be accessed from anywhere in this particular code file
static int someStaticVariable;
// "someArgument" is allocated on the stack each time MyFunction is called
// "someArgument" is deallocated when MyFunction returns
// scope - can be accessed only within MyFunction()
void MyFunction(int someArgument) {
// Statically allocated in the data segment when the program is first loaded
// Deallocated when the program/DLL exits
// scope - can be accessed only within MyFunction()
static int someLocalStaticVariable;
// Allocated on the stack each time MyFunction is called
// Deallocated when MyFunction returns
// scope - can be accessed only within MyFunction()
int someLocalVariable;
// A *pointer* is allocated on the stack each time MyFunction is called
// This pointer is deallocated when MyFunction returns
// scope - the pointer can be accessed only within MyFunction()
int* someDynamicVariable;
// This line causes space for an integer to be allocated in the heap
// when this line is executed. Note this is not at the beginning of
// the call to MyFunction(), like the automatic variables
// scope - only code within MyFunction() can access this space
// *through this particular variable*.
// However, if you pass the address somewhere else, that code
// can access it too
someDynamicVariable = new int;
// This line deallocates the space for the integer in the heap.
// If we did not write it, the memory would be "leaked".
// Note a fundamental difference between the stack and heap
// the heap must be managed. The stack is managed for us.
delete someDynamicVariable;
// In other cases, instead of deallocating this heap space you
// might store the address somewhere more permanent to use later.
// Some languages even take care of deallocation for you... but
// always it needs to be taken care of at runtime by some mechanism.
// When the function returns, someArgument, someLocalVariable
// and the pointer someDynamicVariable are deallocated.
// The space pointed to by someDynamicVariable was already
// deallocated prior to returning.
return;
}
// Note that someGlobalVariable, someStaticVariable and
// someLocalStaticVariable continue to exist, and are not
// deallocated until the program exits.
区分寿命和范围之所以重要,一个特别令人印象深刻的例子说明为什么区分寿命和范围很重要,那就是变量可以具有本地范围,但有静态的寿命,例如,在上文的代码样本中“某些本地静态可变性 ” 。这些变量可以使我们共同但非正式的命名习惯非常混乱。例如,当我们说“某些本地可变性 ” 。当地当地" 我们通常是指 "本地覆盖范围自动分配变量" 当我们说全球时,我们通常指 "全球范围静态分配可变数" 不幸的是,当它谈到类似的事情"缩放的静态分配变量"很多人只是说..."对不对?".
C/C++中的一些语法选择加剧了这一问题,例如许多人认为全球变量并非“静态”,
int var1; // Has global scope and static allocation
static int var2; // Has file scope and static allocation
int main() {return 0;}
请注意, 将关键字“ 静态” 放在上面的声明中会防止 var2 具有全球范围。 然而, 全球 val1 具有静态分布。 这不是直观的。 因此, 我试图在描述范围时从不使用“ 静态” 一词, 而是说“ 文件” 或“ 文件有限” 的范围。 但是许多人使用“ 静态” 或“ 静态范围” 来描述一个只能从一个代码文件中访问的变量。 在生命周期中, “ 静态” 是指“ 静态” 或“ 文件有限” 的范围。 但是许多人使用“ 静态” 或“ 静态范围” 来描述一个只能从一个代码文件中访问的变量。始终始终表示变量在程序启动时分配,在程序退出时进行交易。
有些人认为这些概念是特定C/C++/C++。它们不是。例如,下面的Python样本说明了所有三种分配类型(在翻译语言方面可能存在一些我无法进入这里的微妙差异)。
from datetime import datetime
class Animal:
_FavoriteFood = 'Undefined' # _FavoriteFood is statically allocated
def PetAnimal(self):
curTime = datetime.time(datetime.now()) # curTime is automatically allocatedion
print("Thank you for petting me. But it's " + str(curTime) + ", you should feed me. My favorite food is " + self._FavoriteFood)
class Cat(Animal):
_FavoriteFood = 'tuna' # Note since we override, Cat class has its own statically allocated _FavoriteFood variable, different from Animal's
class Dog(Animal):
_FavoriteFood = 'steak' # Likewise, the Dog class gets its own static variable. Important to note - this one static variable is shared among all instances of Dog, hence it is not dynamic!
if __name__ == "__main__":
whiskers = Cat() # Dynamically allocated
fido = Dog() # Dynamically allocated
rinTinTin = Dog() # Dynamically allocated
whiskers.PetAnimal()
fido.PetAnimal()
rinTinTin.PetAnimal()
Dog._FavoriteFood = 'milkbones'
whiskers.PetAnimal()
fido.PetAnimal()
rinTinTin.PetAnimal()
# Output is:
# Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is tuna
# Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is steak
# Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is steak
# Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is tuna
# Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is milkbones
# Thank you for petting me. But it's 13:05:02.256000, you should feed me. My favorite food is milkbones
什么是堆叠?
堆叠是一堆物体, 通常是排列整齐的物体。
计算机结构中的堆叠是数据以 " 最先进 " 方式添加或删除的内存区域。
在多行应用程序中,每串线索都有自己的堆叠。
什么是堆积物?
堆积成堆的杂乱无章的堆积物,
在计算结构中,堆积是一个动态分配的内存领域,由操作系统或内存管理库自动管理。
在方案执行期间,堆积物上的内存被分配、分配和调整,并定期调整大小,这可能导致一个称为碎裂的问题。
当内存物体在小空格内分配时,就会发生碎片,而内存物体之间的空格太小,无法再持有更多的内存物体。
净结果为无法用于进一步分配内存的堆积空间的百分比。
两者加在一起
在一个多行应用程序中, 每串线索都有自己的堆叠。 但是, 所有不同的线条都会共享堆叠 。
因为不同的线条在一个多行应用程序中共享堆积, 这还意味着线条之间必须有一些协调, 以免它们试图同时访问和操作堆积中的同一块内存 。
哪个速度更快 堆叠还是堆叠 为什么?
堆叠比堆积要快得多
这是因为记忆在堆叠上分配的方式。
堆疊上的内存分配和移动堆叠指针一样简单。
对于新编程的人来说,
因为堆栈很小, 当您知道数据需要多少内存时, 或者如果您知道数据大小非常小时, 您会想要使用它 。
最好在知道数据需要大量内存时使用堆积, 或者你只是不确定你需要多少内存(如动态数组)。
Java 内存模型
堆栈是存储本地变量(包括方法参数)的内存区域。当涉及到对象变量时,这些只是堆积中实际对象的引用(指针)。
每次一个对象被即时化时,都会留出一块堆积内存以保持该对象的数据(状态)。由于对象可以包含其他对象,有些数据实际上可以保留这些嵌套对象的引用。
堆叠 :
- 存储在计算机内存中 就像堆积物一样
- 堆叠上创建的变量将超出范围, 自动进行交易 。
- 与堆积上的变量相比,分配速度要快得多。
- 采用实际的堆叠数据结构。
- 存储本地数据, 返回地址, 用于通过参数 。
- 当堆叠使用过多时(大部分来自无限重现或过深重重循环,分配量很大), 堆叠就会溢出。
- 在堆栈上创建的数据可以不用指针使用 。
- 如果您确切知道在编译时间之前需要分配多少数据, 并且数据并不太大, 您就会使用堆叠 。
- 通常在程序启动时已经确定了最大尺寸 。
热量 :
- 存储在计算机内存 和堆叠一样。
- 在 C+++ 中, 堆积上的变量必须手动销毁, 并且绝对不能脱离范围。 数据以
delete
,delete[]
,或free
. - 相对于堆叠上的变量, 较慢分配速度 。
- 用于按需分配一组数据供程序使用。
- 当有大量拨款和交易时,就有可能支离破碎。
- 在C++ 或C++ 或C中,在堆积上生成的数据将用指针指出,并用
new
或malloc
两者分别。 - 如果要求分配的缓冲量太大,则可以造成分配失败。
- 如果您不知道运行时需要多少数据, 或者需要分配大量数据, 您就会使用这种数据 。
- 负责内存泄漏
示例:
int foo()
{
char *pBuffer; //<--nothing allocated yet (excluding the pointer itself, which is allocated here on the stack).
bool b = true; // Allocated on the stack.
if(b)
{
//Create 500 bytes on the stack
char buffer[500];
//Create 500 bytes on the heap
pBuffer = new char[500];
}//<-- buffer is deallocated here, pBuffer is not
}//<--- oops there's a memory leak, I should have called delete[] pBuffer;
CPU堆和堆肥与CPU和登记簿如何与记忆工作、机器组合语言如何运作、而不是高层次语言本身有实际联系,即使这些语言能决定小事。
所有现代CPU都与“相同”微处理理论合作: 它们都基于所谓的“ 注册者” 和一些“ 堆叠” 来取得性能。 所有 CPU 从一开始就有堆叠登记簿, 并且他们总是在这里, 正如我所知。 议会语言从一开始就是相同的, 尽管有各种变化... 直到微软及其中间语言(IL) 改变了范式, 有了OO虚拟机组装语言。 因此, 我们将来可以有一些 CLI/ CIL CPU (一个MS项目) 。
CPU有堆叠登记册来加速存取记忆,但与其他登记册相比,这些登记册有限,无法完全获取进程的所有可用内存。 这就是为什么我们谈论堆叠和堆积分配的原因。
简而言之,总的来说,堆积是慢慢的,用于“全球”实例和对象内容,因为堆叠的体积很小,速度很快,用于“本地”变量和参考(隐藏的指针要忘记管理它们)。
所以当我们用一种方法使用新关键字时, 引用( int) 是在堆叠中创建的, 但是对象及其所有内容( 价值类型以及对象) 都在堆积中创建, 如果我记得的话。 但是本地基本值类型和阵列是在堆叠中创建的 。
内存存存取的差别在于单元格参考级别:处理堆积,即整个过程的记忆,在处理CPU登记册方面要求比处理堆叠更为复杂,因为如果我记得,CPU堆叠登记册被用作基地址,因此,处理堆积存存存存取的差别就大于当地“更多”的堆叠。
这就是为什么当我们有非常长或无限的循环电话或循环时, 我们很快地被堆积物溢出, 而不冻结现代电脑上的系统...
C# Heap(ing) Vs Stack(ing) in.NET
https://en.wikipedia.org/wiki/Memory_management
https://en.wikipedia.org/wiki/Stack_register
大会语文资源:
推荐文章
- 如何找到Java堆大小和内存使用(Linux)?
- 为什么不使用异常作为常规的控制流呢?
- 什么是序列化?
- 每个递归都可以转换成迭代吗?
- 在Objective-C中@property保留,赋值,复制,非原子
- Python内存泄漏
- 什么是ORM,它是如何工作的,我应该如何使用它?
- 我能在服务器端应用程序(PHP、Ruby、Python等)上读取URL的哈希部分吗?
- 多少个参数是太多?
- 对于不可变集合上的非突变“add”方法,最好的名称是什么?
- Go中结构体的堆栈与堆分配,以及它们与垃圾收集的关系
- brk()系统调用做什么?
- foo到底是什么意思?
- foreach和map有区别吗?
- 为什么我应该使用Deque而不是Stack?