我查了一下,但对这三个概念不太理解。我什么时候必须使用动态分配(在堆中)以及它的真正优势是什么?静态和堆栈有什么问题?我可以编写整个应用程序而不在堆中分配变量吗?
我听说其他语言包含“垃圾收集器”,因此您不必担心内存。垃圾收集器做什么?
你可以自己操作内存做哪些使用垃圾收集器做不到的事情?
曾经有人对我说,有了这样的声明:
int * asafe=new int;
我有一个“指向指针的指针”。这是什么意思?它不同于:
asafe=new int;
?
类似的问题被问到,但它没有询问静力学。
静态内存、堆内存和堆栈内存的概述:
-
静态变量基本上是一个全局变量,即使您无法全局访问它。通常,可执行文件本身有一个地址。整个程序只有一份副本。无论您进入函数调用(或类)多少次(以及在多少个线程中!),变量都引用相同的内存位置。
-
堆是一堆可以动态使用的内存。如果你想要一个对象 4kb,那么动态分配器将查看堆中的可用空间列表,挑选一个 4kb 块,然后将其提供给你。通常,动态内存分配器(malloc、new 等)从内存末尾开始并向后工作。
-
解释堆栈如何增长和收缩有点超出了这个答案的范围,但足以说明您总是只从末尾添加和删除。堆栈通常从高地址开始,然后向下增长到较低的地址。当堆栈在中间某处遇到动态分配器时,您就会耗尽内存(但请参考物理内存与虚拟内存和碎片)。多个线程将需要多个堆栈(进程通常为堆栈保留一个最小大小)。
当您想要使用每一个时:
-
静态/全局变量对于您知道始终需要并且永远不想释放的内存非常有用。 (顺便说一句,嵌入式环境可能被认为只有静态内存......堆栈和堆是由第三种内存类型共享的已知地址空间的一部分:程序代码。程序通常会对其进行动态分配当它们需要诸如链表之类的东西时,静态内存。但无论如何,静态内存本身(缓冲区)本身并不是“分配”的,而是为此目的从缓冲区所持有的内存中分配了其他对象。您可以这样做在非嵌入式中也是如此,控制台游戏经常会避开内置的动态内存机制,转而通过对所有分配使用预设大小的缓冲区来严格控制分配过程。)
-
当您知道只要函数在作用域内(在堆栈上的某个位置),您就会希望保留变量时,堆栈变量非常有用。堆栈对于它们所在的代码需要但在该代码之外不需要的变量来说非常有用。当您访问资源(例如文件)并希望资源在您离开该代码时自动消失时,它们也非常有用。
-
当您想要比上述更灵活时,堆分配(动态分配的内存)非常有用。通常,会调用函数来响应事件(用户单击“创建框”按钮)。正确的响应可能需要分配一个新对象(一个新的 Box 对象),该对象应在函数退出后很长时间内保留,因此它不能位于堆栈上。但您不知道在程序开始时需要多少个盒子,因此它不可能是静态的。
垃圾收集
最近我听说了很多关于垃圾收集器有多么出色的说法,所以也许一些反对的声音会有所帮助。
当性能不是一个大问题时,垃圾收集是一个很好的机制。我听说 GC 变得越来越好、越来越复杂,但事实是,您可能被迫接受性能损失(取决于用例)。如果你很懒,它仍然可能无法正常工作。在最好的情况下,垃圾收集器会意识到,当它意识到不再有对它的引用时,您的记忆就会消失(请参阅引用计数)。但是,如果您有一个引用自身的对象(可能通过引用另一个引用回来的对象),那么单独的引用计数并不表明可以删除内存。在这种情况下,GC 需要查看整个引用汤并找出是否存在仅由其自身引用的岛屿。顺便说一句,我猜这是一个 O(n^2) 操作,但无论它是什么,如果您完全关心性能,它可能会变得很糟糕。 (编辑:马丁·B指出对于相当高效的算法来说,它的复杂度是 O(n)。如果您关心性能并且可以在恒定时间内释放而不进行垃圾回收,那么这仍然是 O(n) 太多。)
就我个人而言,当我听到人们说 C++ 没有垃圾收集时,我的想法是将其标记为 C++ 的一个功能,但我可能属于少数。对于人们来说,学习 C 和 C++ 编程最难的事情可能是指针以及如何正确处理动态内存分配。其他一些语言,比如 Python,如果没有 GC,就会很糟糕,所以我认为这取决于你想要从语言中得到什么。如果你想要可靠的性能,那么没有垃圾回收的 C++ 是我能想到的 Fortran 方面唯一的东西。如果您想要易用性和辅助轮(为了避免崩溃,而不需要您学习“正确的”内存管理),请选择带有 GC 的东西。即使您知道如何很好地管理内存,它也会节省您的时间,您可以将这些时间用于优化其他代码。实际上不再有太大的性能损失,但如果您确实需要可靠的性能(以及准确了解幕后发生的情况、时间和情况的能力),那么我会坚持使用 C++。我听说过的每个主要游戏引擎都是 C++ 语言(如果不是 C 语言或汇编语言),这是有原因的。 Python 等语言适合编写脚本,但不适用于主要游戏引擎。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)