大数组、std::vector和堆栈溢出
large arrays, std::vector and stack overflow
我有一个从大数组中读取数据的程序,我最初在Visual Studio中将该程序分为两个单独的项目,每个项目都运行良好,但当我试图将它们放在一起时,程序在调试时跳过了一些步骤,表现得很有趣。我对C++很陌生,所以我开始做一些研究,我发现也许我用那些巨大的数组填充了堆栈,我应该试着把它们放在堆上。
我决定为std::vector
更改每个数组,并以这种方式初始化它们:
std::vector<double> meanTimeAO = { 0.4437, 0.441, 0.44206, 0.44632, 0.4508, 0.45425,...}
但是,在更改了所有数组之后,当我试图编译编译器时,由于堆栈溢出而崩溃,我认为我通过将数组更改为向量来从堆栈中释放内存空间,但似乎我得到了相反的结果,为什么??
我应该如何处理这些大数组?(它们是固定的,从不改变值或大小)
正如@Ajay的回答和@Cornstrails的评论正确指出的那样,您可以通过在数组上使用static
或constexpr
限定符来完全避免堆栈和堆
const static std::array<float, 1000000> a1 = {}; // OK
constexpr std::array<float, 1000000> a2 = {}; // OK in C++11 onwards
这将数组存储在内存的数据初始化部分(这里有很好的解释)。const
仅用于禁止修改a1
,不需要它来避免堆栈溢出。声明为constexpr
的变量也自动为const
,因此不需要限定符。
注意:您也可以通过使数组成为全局变量来实现static
的效果,尽管我不建议这样做。
程序堆栈溢出
如果数据是非静态的,那么当元素数量很大时,应该使用std::vector
(或其他类型的堆分配内存)。
std::array<float, 1000000> a = {}; // Causes stack-overflow on 32-bit MSVS 2015
std::vector<float> v(1000000); // OK
这是因为默认堆栈大小约为1MB,100万个浮点需要约4MB。堆的大小受到系统可用内存(RAM)的限制。更多信息请点击此处。
std::vector
的缺点是它比std::array
慢一点(堆内存分配、释放和访问都比堆栈慢),而且它不是固定大小。但是,您可以将std::vector
声明为const
,以防止自己(或其他人)意外更改其大小或元素。
const std::vector<float> v = {...};
现在,为什么std::vector
会导致堆栈溢出还有点神秘。然而,当std::vector
在堆上分配其元素时,它也在堆栈上分配指针(32位上为4字节,64位上为8字节)。因此,如果同时有超过250000个std::vector
,这也会导致堆栈溢出(在64位系统上约为125000)。
编译器堆栈溢出
编译器和任何程序一样,分配内存——其中一些内存将在堆栈上。MSVC上编译器堆栈溢出的官方错误是致命错误C1063。
考虑到调试器的行为很奇怪,我的建议是尝试通过手动将代码拆分为模块单元并单独编译来隔离有问题的代码。少量的代码可能会消耗大量的堆栈,例如递归地生成大量的函数,从而导致错误。
或者,您的代码可能天生就很复杂,因此它自然需要比堆栈更多的内存。在这种情况下,拆分代码仍然有好处,但您也可以尝试增加MSVC的默认堆栈大小。
改进您的代码
为了改进您的代码,您可以尝试将数据拆分为块。例如,您可以:读取大约256 KB的数组,对其进行处理,将数组写回文件,然后转到下一个256 KB。您可以进一步选择块的大小小于一级缓存的大小(这样就可以同时存储所有块),这将通过最大限度地减少缓存未命中来提高性能。
备注
MSVS 2015(更新2)在编译时产生内部编译器错误
#include "stdafx.h" #include <array> int main() { constexpr std::array<int, 1000000> a = {}; return 0; }
static const
变体运行良好,如果我将a
移到main之外(使其成为全局变量),那么它也运行良好。没有chkstk.asm是不寻常的。矿山位于
C:Program Files (x86)Microsoft Visual Studio 14.0VCcrtsrci386chkstk.asm
。如果您丢失了它,那么也许可以尝试重新安装MS Visual Studio。
如果数组是固定大小的,并且其元素不变,那么就不需要使用vector
。您可以使用std::array
、const
数组或constexpr
。
constexpr float meanTimeAO[] = { 0.4437f, 0.441f, 0.44206f, 0.44632f, 0.4508f, 0.45425f,...}
指出以上答案中可能忽略的几点:
-
"程序在调试时跳过了一些步骤,表现得很有趣"。OP,你能提供更多关于你的意思的细节吗?也许,您正在调试一个发布版本,当您遍历代码时,您会发现正在执行的代码行不是您期望下一步执行的代码(这对于具有编译器优化的发布版本来说是完全正确的行为)。
-
问题指出编译器因堆栈溢出而崩溃。不是执行的程序。所以问题是编译器的问题。当然,更改代码可能会使编译器不会崩溃,但上面关于在堆栈上分配std::vector的注释与导致编译器崩溃的原因无关。
建议:您可以尝试查看您使用的编译器版本中是否存在任何已知的错误(即,查看您的编译器供应商是否发布了可能解决编译器崩溃问题的最新版本)。
此外,特别是在你的"它们的值或大小从未改变"评论中,试着将数据放入静态常量双数组,而不是std::vectors(甚至链表)。当您可能只应该使用double[]时,一个不变的静态分配的只读链表有点浪费时间。静态const数据是在编译/链接时而不是运行时初始化的,并且存在于自己的内存区域中(严格来说,既不是堆栈也不是堆)。
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 我的 int main() 中出现堆栈溢出错误
- C++ 对象数组堆栈溢出
- 有没有一种方法可以捕获进程中的堆栈溢出?C++Linux
- 对象接收堆栈溢出异常 c++ 的排序向量
- 将公共递归转换为尾递归,因为大型输入的堆栈溢出
- C++ 中递归期间的堆栈溢出
- 启动 dll 时 C# 环境堆栈溢出
- 在C++中使用数组时如何防止堆栈溢出?
- 如何修复递归函数导致的堆栈溢出错误?C++
- 当我尝试为结构分配新指针时出现堆栈溢出错误
- 为什么析构函数无休止地调用自己(导致堆栈溢出)?
- 为什么堆栈溢出?如有建议,不胜感激
- 主函数执行时C++堆栈溢出异常
- 如何在不导致堆栈溢出的情况下计算非常大的数字和很小的 HCF.我正在使用欧几里得算法
- 我正在尝试使用回溯来解决 N queen 问题,但在编译时它会给出运行时错误(动态堆栈缓冲区溢出)
- 如何在Windows上报告堆栈缓冲区溢出
- 如何抑制来自 gcc 中地址清理器的堆栈缓冲区溢出
- 声明大数组时堆栈/堆溢出
- c++中栈溢出和分段错误的危险