堆叠和堆肥是什么?它们实际上位于计算机的内存中在哪里?它们在多大程度上被操作时间或语言控制?它们的范围是什么?它们的大小是什么?它们大小是什么?一个的大小是什么使一个更快?


当前回答

堆叠基本上是一个容易获取的内存,它只是将项目管理成一个 - 井 - 堆叠。只有事先知道其大小的物品才能进入堆叠。数字、字符串、布林恩就是这种情况。堆叠是无法预设准确大小和结构的物品的内存。由于天体和阵列可以在运行时变形和改变,它们必须进入堆叠。

源源代码:academinide

其他回答

简单的说, 堆栈是创建本地变量的地方。 另外, 每次您调用一个子例程, 程序计数器( 下个机器指令的指针) 和任何重要的注册器, 有时参数会被推到堆栈上。 然后子例程内的任何本地变量都会被推到堆叠上( 并在那里使用 ) 。 当子例程完成时, 所有的事物都会从堆栈中跳出来。 pc 和 注册数据会得到并放回原位, 所以您的 progra 就会被推到堆叠上( 并在那里使用 ) 。

它是一个特殊的数据结构,可以跟踪不同大小的记忆区块及其分布状况。

在“古典”系统上, 堆叠指针是放在记忆底部开始的, 堆积指针是从顶部开始的, 并且它们相互向上发展。 如果它们重叠, 你就会脱离公羊。 但是, 与现代多孔的套索不起作用。 每条线必须有自己的堆叠, 并且它们可以动态地生成 。

许多答案作为概念是正确的,但我们必须指出,硬件(即微处理器)需要堆叠,才能调用子例程(用组装语言调用)。 (oop guys will call it ways)

在您保存返回地址的堆栈上, 并拨“ 推 / 重 ” Pop 由硬件直接管理 。

您可以使用堆叠来设定通过参数。 即使比使用登记册要慢( 微处理器大师会说, 或者好的 1980 年代生物书...) )

没有堆叠, 没有微处理器是行不通的。 (我们无法想象一个程序, 即使是在组装语言中, 没有子例程/功能) 没有它能工作的堆肥( 组装语言程序可以工作, 因为堆肥是一个 os 概念, 作为 malloc, 是一个 os/lib调用 ) 。

堆栈使用速度更快, 以 :

硬体是硬件,甚至推/棒也非常有效。 中转器需要输入内核模式,使用锁/石墨(或其他同步原始元素)执行某些代码,并管理一些跟踪分配情况所需的结构。

其他答案只是避免解释静态分配意味着什么。 所以我会解释三种主要分配形式,以及它们通常与下面的堆积、堆叠和数据段的关系。 我还会在 c/c++ 和 python 中展示一些例子,以帮助人们理解。

静态( 静态分配) 变量没有在堆叠上分配。 不要假设- 许多人只是因为“ 静态” 听起来像“ 堆叠 ” 。 它们实际上既不存在于堆叠中, 也不存在于堆叠中。 它们属于所谓的数据段 。

然而,一般而言,最好考虑“范围”和“终生”,而不是“堆积”和“堆积”。

范围指代码中哪些部分可以访问变量。 我们一般认为本地范围(只能通过当前函数访问)与全球范围(任何地方都可以访问)不同,尽管范围可能变得更加复杂。

当一个变量在程序执行期间被分配和交易时, 其使用寿命值是指变量在程序执行期间被分配和交易。 我们通常会想到静态分配( 在整个程序期间会持续不变, 使得它可用于在多个函数调用中存储相同的信息), 而会想到自动分配( 仅在对函数的单次调用中持续不变, 使得它可用于存储仅在您函数期间使用、 一旦完成即可丢弃的信息) 相对于动态

尽管大多数编译者和口译员在使用堆叠、堆堆堆等方面也采取了类似的做法,但只要行为正确,编译者有时会打破这些公约。例如,由于优化,本地变量可能只存在于登记册中,或者完全删除,即使大多数本地变量存在于堆叠中。正如在几个评论中所指出的,你可以自由实施一个甚至不使用堆叠或堆叠的编译者,但有些则可以使用

i 将提供一些简单的附加说明的 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++/ 具体化的。 它们不是。 例如,下面的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

短短

a 堆叠用于静态内存分配和动态内存分配,两者都储存在计算机的顶部。


详细详细

堆叠堆叠

堆栈是一个“ lifo”( 最后一个, 第一个出来) 数据结构, 由 cupu 非常密切地管理和优化。 每次函数在显示新的变量时, 它会“ 挂在” 堆栈上。 然后, 每次函数退出, 所有被该函数推到堆栈的变量都被解开( 也就是说, 它们被删除 ) 。 一旦打开堆叠变量, 内存区域就会为其他堆叠变量提供 。

使用堆叠存储变量的优点是, 内存被管理 。 您不需要用手来分配内存, 也无需在不再需要时释放内存 。 更何况, 因为 CDP 组织堆叠内存的效率如此高, 读取和写入到堆叠变量的速度非常快 。

在此可以找到更多 。


堆积物,

计算机的内存区域不自动管理, 也不由 cpu 进行严格管理。 它是一个更自由的内存区域( 且更大) 。 要在堆中分配内存, 您必须使用 bloc () 或 calloc () , 它们是内嵌的 c 函数 。 一旦您在堆中分配内存, 您就有责任使用 free () 来在不再需要内存时处理内存 。

如果您不这样做, 您的程序将会有所谓的内存泄漏。 也就是说, 堆积上的内存仍将被搁置( 并且无法用于其它进程 ) 。 正如我们在调试部分看到的那样, 有一个名为 valgrind 的工具可以帮助您检测内存泄漏 。

与堆叠不同, 堆积的大小没有变量大小限制( 除了您的计算机的明显物理限制之外 ) 。 堆积的内存读和书写要慢一点, 因为需要用指针来访问堆积的内存 。 我们很快会讨论指针问题 。

与堆叠不同的是,在堆积上创建的变量可以被任意函数进入,在您的程序中的任何地方。堆积变量在范围上基本上是全球性的。

在此可以找到更多 。


堆栈上分配的变量直接存储到内存中, 访问此内存的时间非常快, 当程序编译时会处理其分配。 当函数或方法调用另一个函数, 转而调用另一个函数等时, 所有这些函数的履行将一直暂停, 直到最后一个函数返回其值。 堆栈总是保留在 lifo 顺序中, 最近保留的块总是下一个要解开的块 。

堆积上分配的变量的内存在运行时间分配,而访问此内存的时间稍慢一些,但堆积大小仅受虚拟内存大小的限制。 堆积中的元素不互相依赖, 随时可以随机访问。 您可以随时分配块块, 并随时释放它。 这使得跟踪堆积中哪些部分在任何特定时间分配或自由, 变得更加复杂 。

如果您确切知道在编译时间之前需要分配多少数据,您可以使用堆叠,而它并不太大。如果您不知道运行时需要多少数据,或者如果您需要分配大量数据,您可以使用堆叠。

在多轨情况下, 每串线索将拥有自己的完全独立的堆叠, 但是它们会共享堆叠 。 堆叠是特定的线条, 堆叠是特定的应用程序 。 堆叠很重要, 在例外处理和丝线处决中需要考虑 。

每一串线索都有堆叠, 而通常应用程序只有一堆(尽管对于不同种类的分配来说, 多堆堆并不罕见) 。

运行时, 如果应用程序需要更多堆肥, 它可以从空闲的内存中分配内存, 如果堆叠需要内存, 它可以从空闲的内存中分配内存, 用于应用程序的内存中分配内存 。

即使如此,这里和这里还有更详细的内容。


现在来回答你的问题吧

在多大程度上它们受国家或语言运行时间控制?

当线索创建时, os 分配每个系统级线索的堆叠。 通常, os 被语言运行时间调用来分配应用程序的堆叠 。

在此可以找到更多 。

其范围是什么?

已经在上方给定 。

“如果你确切知道在编译时间之前你需要分配多少数据,你可以使用堆叠。它并不太大。如果你不知道运行时你需要多少数据,或者你需要分配很多数据,你可以使用堆叠。”

在此可以找到更多 。

是什么决定了每个孩子的大小?

当创建线索时,堆栈的大小由 OS 设定。 程序启动时会设置堆积的大小, 但随着需要空间, 堆堆的大小会扩大( 分配器要求操作系统有更多的内存 ) 。

是什么让一个更快?

堆叠分配速度要快得多, 因为实际上它所做的就是移动堆叠指针。 使用内存池, 您可以从堆积分配中获取相似的性能, 但是这伴随着稍微增加的复杂性和它本身的头痛。

此外,堆叠对堆肥不仅是对性能的考量;它也告诉你很多关于物体的预期寿命。

在此可以找到细节 。

我想其他很多人 已经给了你 大部分正确的答案 关于这件事情。

然而,一个被忽略的细节是,“堆积”实际上可能应该被称为“免费商店”。 之所以有这种区别,是因为最初的免费商店是用被称为“二成式堆肥”的数据结构来安装的。 因此,从早期实施中分配的麦洛克()/免费()是从堆肥中分配的。 然而,在现代,大多数免费商店都是用非常精密的数据结构来安装的,而不是二成式堆肥。