C++ - 本地堆栈数组与动态分配

13 c++ stack-overflow

用C/C++编程时; 根据经验,什么是切断点,而不是char array[MAX_PATH+1]={0}一个人会使用:

 char *array=nullptr;

 array=new char [MAX_PATH+1];

 ...code...

 delete [] array;
Run Code Online (Sandbox Code Playgroud)

人们在什么时候采取行动来保留堆叠上的空间?

20年前,我被告知你应该在堆上分配超过32个字节的所有数组,无论性能成本如何,并为简单变量保存堆栈.我已经看到很多现代示例代码非常使用堆栈,所以这种想法改变了吗?

小智 8

堆栈分配的好处是您不必检查失败,您不必担心内存碎片,并且在函数返回时自动释放内存.缺点是您无法检查是否成功,并且通常在失败时会发生错误.

没有虚拟内存(例如,在小型微控制器上),通常可用的内存较少.如果你的程序在堆栈上分配了太多的空间,它只会溢出堆栈并写入超出为堆栈保留的空间之外的任何内容.您可以留出更多的堆栈空间来处理最坏的情况,但无论您是否需要,该空间始终专用于堆栈.而使用动态分配时,您只需在使用它时付费,并且可以检查返回代码malloc以确定是否发生了故障(或者new为尝试将C++压缩到微控制器的人捕获异常).或者,如果应用程序始终需要,您可以静态地为对象保留一部分RAM,因为这样可以更加可预测的运行时行为,并且您不必担心碎片.

通过虚拟内存,操作系统可以通过在堆栈末尾向连续的虚拟地址添加页面来动态扩展堆栈.这样,您只需为您正在使用的金额堆栈支付物理内存.但是,如果有一个小的(32位或更少?)地址空间,如果你有很多线程和太多的堆栈分配,你仍然会遇到麻烦.

每个线程必须为其堆栈提供连续的空间,并且必须与系统中的其他所有内容共享.例如,如果操作系统占用1 GB的地址空间(并非罕见),并且您希望1 GB用于线程堆栈,则会为堆,数据和代码留下2 GB的空间.如果您有16个线程,这意味着每个线程堆栈可以有大约64 MB.根据您的应用程序,可能会或可能不会.

如果您有更多线程或更大的堆栈分配对象,则必须调整线程堆栈大小和堆大小以获得正确的平衡.如果你错了,你的程序分段会在堆栈溢出时出错.因此,建议在堆上进行所有"大"分配,因为更可预测的运行时行为.

20年前,4 GB的地址空间为堆,数据,代码和堆栈提供了大量空间 - 今天并不多.幸运的是,地址空间也变得更大了.使用64位地址空间,即使您有超过1 TB的DRAM,在耗尽物理内存之前,您将耗尽DRAM.

几个警告

  1. 运行时通常会对堆栈大小进行任意限制,以捕获失控的递归错误.如果你使用的堆栈比运行时系统预期的多得多,你可能需要告诉它给你一个更大的堆栈.通常,默认大小足够大,通常不难改变.

  2. 操作系统/运行时不像回收堆栈空间那样好.由于您的程序需要更多的堆栈空间,因此它将获得新页面.在线程退出之前很可能不会释放这些页面(至少在那种情况下是这样).如果您正在使用堆栈空间,那不是什么大问题.如果它很少使用并且线程运行很长时间,如果你有后备存储器,内存将被交换到磁盘(对于带有旋转驱动器的台式机/笔记本电脑通常不是问题,但对于iOS8或Android 64可能不太好)位).

如果您希望您的代码在具有大量物理和虚拟内存空间的系统上运行,而您计划堆栈分配的对象,则堆栈分配可能正常.在大多数情况下,收益将超过成本.


Bee*_*eed 4

链接器设置堆栈大小。在 Windows 上,任何静态分配最多将处理 1 GB(在其他系统上可能有所不同)。然而,Windows 上的默认堆栈大小为 1MB(Linux 上为 8MB)。因此,动态分配的主要好处是您事先不知道大小,或者您的程序是否需要一些非常大的分配。

  • 链接器仅设置某些系统的堆栈大小。 (3认同)