小编典典

C++ 中的堆栈、静态和堆

all

我搜索过,但我对这三个概念不是很了解。我什么时候必须使用动态分配(在堆中),它的真正优势是什么?静态和堆栈的问题是什么?我可以编写整个应用程序而不在堆中分配变量吗?

我听说其他语言包含“垃圾收集器”,因此您不必担心内存。垃圾收集器是做什么的?

你能做些什么来自己操作内存,而使用这个垃圾收集器是做不到的?

曾经有人用这个宣言对我说:

int * asafe=new int;

我有一个“指向指针的指针”。这是什么意思?它是不同的:

asafe=new int;

?


阅读 58

收藏
2022-08-16

共1个答案

小编典典

什么是静态、堆和堆栈内存的总结:

  • 静态变量基本上是全局变量,即使您无法全局访问它。通常在可执行文件本身中有一个地址。整个程序只有一个副本。无论您进入函数调用(或类)多少次(以及在多少个线程中!),该变量都指向相同的内存位置。

  • 堆是一堆可以动态使用的内存。如果你想要一个 4kb 的对象,那么动态分配器将查看它在堆中的可用空间列表,挑选出一个 4kb 的块,然后给你。通常,动态内存分配器(malloc、new 等)从内存末尾开始并向后工作。

  • 解释堆栈如何增长和缩小有点超出了这个答案的范围,但只要说你总是从最后添加和删除就足够了。堆栈通常从高位开始并向下增长到较低的地址。当堆栈在中间某处遇到动态分配器时,您会耗尽内存(但指的是物理内存与虚拟内存和碎片)。多个线程将需要多个堆栈(进程通常为堆栈保留最小大小)。

当您想使用每一个时:

  • 静态/全局对于您知道您将始终需要并且您知道您永远不想释放的内存很有用。(顺便说一句,嵌入式环境可能被认为只有静态内存......堆栈和堆是由第三种内存类型共享的已知地址空间的一部分:程序代码。程序通常会从它们的当他们需要链表之类的东西时使用静态内存.但无论如何,静态内存本身(缓冲区)本身并不是“分配的”,而是其他对象为此目的从缓冲区持有的内存中分配出来.你可以这样做在非嵌入式中也是如此,主机游戏会经常避开内置的动态内存机制,转而通过对所有分配使用预设大小的缓冲区来严格控制分配过程。)

  • 当您知道只要函数在范围内(在某处的堆栈上),您会希望变量保留时,堆栈变量很有用。堆栈非常适合您所在的代码所需的变量,但在该代码之外不需要。当您访问资源(如文件)并希望资源在您离开该代码时自动消失时,它们也非常有用。

  • 当您想要比上述更灵活时,堆分配(动态分配的内存)很有用。通常,调用函数来响应事件(用户单击“创建框”按钮)。正确的响应可能需要分配一个新对象(一个新的 Box 对象),该对象在函数退出后应该保留很长时间,因此它不能在堆栈上。但是你不知道在程序开始时你想要多少个盒子,所以它不能是静态的。

垃圾收集

我最近听到很多关于垃圾收集器有多棒的消息,所以也许有点反对的声音会有所帮助。

当性能不是一个大问题时,垃圾收集是一种很好的机制。我听说 GC
越来越好,越来越复杂,但事实是,您可能被迫接受性能损失(取决于用例)。如果你很懒惰,它仍然可能无法正常工作。在最好的情况下,垃圾收集器会意识到,当它意识到不再有对它的引用时,你的记忆就会消失(参见引用计数)。但是,如果您有一个引用自身的对象(可能通过引用另一个引用回来的对象),那么单独的引用计数并不能表明可以删除内存。在这种情况下,GC
需要查看整个参考汤,并确定是否存在任何仅由它们自己参考的岛。顺便说一句,我猜这是一个 O(n^2)
操作,但不管它是什么,如果你完全关心性能,它可能会变得很糟糕。(编辑:Martin
B指出,对于相当有效的算法来说,它是
O(n)。如果您关心性能并且可以在没有垃圾收集的情况下在恒定时间内解除分配,那仍然是 O(n) 太多。)

就我个人而言,当我听到人们说 C 没有垃圾收集时,我认为这是 C 的一个特性,但我可能是少数。人们学习 C 和 C
编程最难的事情可能是指针以及如何正确处理它们的动态内存分配。其他一些语言,比如 Python,如果没有
GC,会很糟糕,所以我认为这归结为你想要从一种语言中得到什么。如果你想要可靠的性能,那么没有垃圾收集的 C
是我能想到的 Fortran
这边唯一的东西。如果您想要易于使用和训练轮子(以使您免于崩溃,而无需您学习“正确的”内存管理),请选择带有 GC
的东西。即使您知道如何很好地管理内存,它也会节省您可以花在优化其他代码上的时间。真的没有太多的性能损失了,但是如果你真的需要可靠的性能(并且能够准确地知道发生了什么,什么时候,在幕后),那么我会坚持使用
C。我听说过的每个主要游戏引擎都使用 C(如果不是 C 或汇编),这是有原因的。Python 等适用于脚本编写,但不适用于主游戏引擎。

2022-08-16