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


当前回答

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

源源代码:academinide

其他回答

您可以用堆叠做一些有趣的事情。例如,您有像 Alloca(假设您能够通过关于堆叠使用的大量警告)这样的功能,这是一种形式的中转器,专门用堆叠而不是堆叠来记忆。

也就是说,基于堆叠的内存错误是我经历过的最糟糕的内存错误。 如果您使用堆积内存, 并且越过分配区块的界限, 您有触发断段故障的好机会 。 ( 不是100%: 您的区块可能附带地与先前分配的区块相毗连 。) 但是由于堆叠上创建的变量总是相互连结, 写出边框可以改变另一个变量的值 。 我了解到, 只要我感觉到, 只要我感觉到它, 就会改变另一个变量的值 。

其他人对大中风的反应也很好, 所以我要说几个细节。

堆叠和堆栈不需要是单数。 通常情况下, 您有一个以上的堆叠, 通常情况下, 您在一个过程中有多个线索。 在此情况下, 每个线索都有自己的堆叠。 您也可以有一个以上的堆叠, 例如, 一些 dll 配置可能导致不同堆堆分配不同的拖曳, 这就是为什么释放由不同库分配的内存通常是一个坏主意 。 c 您可以通过使用 Alloc 获得可变长度分配的好处 。

void myfunction()
{
   char big[10000000];
   // Do something that only uses for first 1K of big 99% of the time.
}

a couple of cents: 我认为, 绘制内存图形比较简单, 将会是件好事 :

箭头 - 显示生长堆叠和堆肥的位置, 进程堆叠大小有限制, 以 os 定义, 以线状线条参数为线状堆叠大小限制通常创建 api 。 通常以进程最大虚拟内存大小为限制, 例如32 位 2-4 gb 。

如此简单的方式:过程堆积对于过程和内部所有线条来说都是一般的, 用于记忆分配, 常见的情况是像 malloc () 。

堆栈是用于存储常见函数返回指针和变量的快速存储存储存储的快速内存, 被处理为函数调用中的参数, 本地函数变量 。

其他答案只是避免解释静态分配意味着什么。 所以我会解释三种主要分配形式,以及它们通常与下面的堆积、堆叠和数据段的关系。 我还会在 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

堆叠 :

堆叠上创建的变量将超出范围,自动交易。 与堆叠上的变量相比, 分配速度要快得多。 使用实际的堆叠数据结构执行。 存储本地数据、 返回地址、 参数通过时使用的方法。 当堆叠过多使用时, 可能会出现堆叠溢出( 大多来自无限或过深的循环, 非常大的配置) 。 堆叠上创建的数据可以在没有指针的情况下使用 。

堆积 :

在 c+++ 中, 堆积上的变量必须手动销毁, 并且绝不会掉出范围 。 数据通过删除、 删除或自由解脱而解脱。 与堆叠上的变量相比, 分配速度较慢。 需要时使用来分配块块数据供程序使用。 当有大量分配和交易位置时, 可能会发生碎裂 。 在 c+++ 或 c 中, 堆积上生成的数据将被指向指针, 并分别与新数据或中位相分配 。

例如:

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;