我听说过有关动态的确切含义的冲突事件,以及自动内存分配.我听说堆栈被称为自动内存分配和动态内存分配.我可以看到两者都是在程序执行之前确定堆栈内存块大小,因此它的最大大小在运行时不会增长.但是,在程序执行期间,当函数数据被推入和弹出堆栈时,堆栈会不断增长和缩小.
那么在这个意义上是不是这种动态内存分配?
如果它是不是混淆只是将堆称为动态?
有人可以帮我澄清一下吗?
编辑:在撰写本文时,我似乎混淆了一些我不知道的概念.堆栈和堆内存管理的低级concpets与C++中相同内容的高级概念之间存在差异.有关此问题的澄清,请参阅下面我接受的答案.
我会尽力清除混乱.首先,学习将低级内存模型概念(堆栈,堆)与c ++级内存概念分开.在C++的世界里,stack
而heap
并不意味着任何远程类似堆栈或堆在低层次的模型.
首先,我们来谈谈低级内存模型.传统上,内存在"堆栈"和"堆"内存之间分配,我将在下面介绍.
堆栈由所谓的"堆栈指针"CPU寄存器管理 - 它始终指示堆栈的顶部,并从高级别存储器地址连续到低级别存储器地址.由于堆栈的顶部始终由寄存器指向,因此不需要任何与堆栈相关的实际内存管理 - 当您需要更多内存时,您只需减少存储在指针中的值 - 这就是您的内存现在,它是被认为是为你分配的.当你不再需要内存时,你会增加值 - 现在内存是'免费的'.显然,这种方法的问题在于它不可持续 - 你不能在块中释放(或分配)内存.因此,如果为3个对象分配内存,A,B,C并且您不再需要对象B,则不需要您可以说B占用的内存可以自由使用 - 单个堆栈指针根本没有能力这样做.
这限制了堆栈内存对"近距离",短期对象的使用 - 当您知道不需要有选择地释放与此范围内分配的对象关联的任何内存时,可以简单地释放所有内存很快他们 这使得堆栈存储器成为函数中定义的变量的理想存储 - 当函数退出时,它们全部被释放.更好的是编译器可以自动为您执行此操作 - 您不必明确告诉编译器何时为每个变量释放内存 - 一旦代码执行离开它的范围,它将自动释放.
值得注意的是,堆栈分配和释放是不可能的 - 它们只需要一个寄存器算术运算.
但是,正如我之前所说,堆栈有局限性.堆内存在这里是为了克服这些 - 并将在下面进行描述.
与堆栈(仅由简单寄存器管理)不同,堆内存由复杂的结构和逻辑支持.您可以从堆中请求内存,并且可以将内存返回到堆,并且可以针对每个对象单独执行.所以,回到我原来的例子,当你为对象A,B和C(所有相同的大小)请求内存,并且不再需要对象B时,你可以返回B的内存并仍然保留A和C.如果你需要创建另一个与之前大小相同的对象D并为它寻求内存,堆可以给你从B返回的内存.虽然不能保证(堆算法非常复杂),这是一个很好的简化.
与堆栈内存不同,管理堆内存有成本,实际上相对较高(特别是在多线程环境中).这就是为什么不应该使用堆内存,如果一个人可以帮助它,但这是一个很大的话题,我现在不打算讨论.
堆内存的一个非常重要的属性是它必须由用户显式管理.您需要在需要时请求内存,在不再需要时将其恢复,并且永远不要使用您已经回复的内存.不遵守这些规则会导致程序泄漏内存 - 即消耗内存而不返回内存,这会导致程序最终耗尽内存 - 以防您不回忆内存; 或导致程序行为不正确(如果您在请求之前或在回馈之后使用内存),因为您将访问不属于您的内存.
无论好坏,C/C++都会使程序员免受那些低级内存概念的影响.相反,该语言指定每个变量都存在于某种类型的存储中,并且它的生命周期由存储类型定义.存储有3种类型,如下所述.
这个存储由编译器"自动"管理(因此名称),并且不需要程序员对它做任何事情.自动变量的一个例子是在函数体内定义的一个:
void foo() { int a; }
a
这是自动的.你不需要担心为它分配内存或者在不再需要它时清理它,并且编译器保证你在输入函数foo()时它会在那里,当你退出foo()时它将不再存在.虽然它可能在堆栈上分配,但绝对不能保证它 - 它也可以放在寄存器中.寄存器比任何内存都快得多,因此编译器会尽可能地使用它们.
存放在静态存储中的变量会一直存在,直到程序退出.同样,开发人员不需要担心他们的生命周期,或者清理内存 - 程序退出后内存将被清除,而不是之前.静态持续时间变量的示例是在任何函数(全局变量)之外定义的变量,函数的静态局部变量以及类的静态成员.在var1下面的代码中,var2和var3都是静态存储中的变量:
代码(带一些内联注释):
int var1; void foo() { static int var2; } class A { static int var3; }
动态存储变量由开发人员控制.当您需要它们时,您需要内存(通常使用malloc
C或new
C++),并且必须在不再需要时将其返回(free
在C中,delete
在C++中).作为开发人员,您应该全神贯注地分配,使用和删除它们,并确保序列永远不会被破坏.没有观察序列是造成新闻的所有重大程序错误的一个主要原因:).幸运的是,C++为您提供了简化此任务的特殊功能和类,但如果您使用C开发,则可以自行完成.在下面的示例中,动态分配var4点的内存.
码:
void foo() { int* var4; // Here is the major source of confusion. var4 itself is **automatic** // you do not need to allocate or free var4 memory, so you can use it // like this: var4 = NULL; // Not an error!!! // However, you can't use the memory var4 points to yet! // Following line would cause incorrect behavior of the program: // *var4 = 42; // NEVER EVER!!! // Instead, you need to allocate the memory first (let's assume, we are in C++ var4 = new int(); // Now the memory was allocated, we can use it *var4 = 42; // Correct! // we no longer need this memory, so let's free it: delete var4; // This did not change var4 itself (unless there is a special case) // so technically, it still points to the memory which was former // belonging to you. But the memory is no longer yours!!! // you can't read or write it! // Following code is bad-bad-bad: // int x = *var4; // NEVER EVER! }
正如您所见,使用动态内存时会出现最谨慎和警告的迹象.这就是为什么在C++中有一些特殊的工具可以使这更容易,并且没有人期望编写我上面写的代码.然而,我的职位已经是路长,在C++所以正确的内存管理将留给另一个场合:)