最近做毕业设计,debug程序。因为计算量较大,所以选择在release模式下计算。碰到两次程序还没有计算完成直接显示退出的情况,网上看了很多博客,感觉都不适用,程序很简单除了eigen没有引用其他的库。
正常情况下
直接闪退
1、栈溢出
尽管把大规模的数组都设置成了全局变量,在实际调试过程中还是遇到了栈溢出的情况。最后发现是由于tarjan算法的递归层次太多,导致栈空间溢出。函数在递归过程中会一直占用栈资源,只有在结束点退出以后,才会释放所有空间。
下面是经典的图论有向图连通分量的搜索tarjan算法,在节点1000000个的情况下,在连通分量较少的情况下tarjan最大需要递归1000000次,c++中int变量是4B,每次函数递归都会有两个变量u,v会因为递归而储存在栈空间中得不到释放,那么最大需要的栈空间是1000000x4B~4MB,而vs2013中一般默认是1MB。修改可以通过
项目->属性->链接器->系统->堆栈保留大小(Stack reserve) 改成10000000就差不多了
//Tarjan's algorithm,Tarjar[1972]
vector<vector<int>> Components;
int Cell_to_Com[N + 1];
int dfn[N + 1] = { 0 }, low[N + 1] = { 0 };
bool instack[N + 1], indfs[N + 1];
int cnt = 0;
stack<int> Stack;
void Tarjan(int u){
int v;
dfn[u] = low[u] = ++cnt;//每次dfs,u的次序号增加1
Stack.push(u);
indfs[u] = true;
instack[u] = true;
for (int i = 0; i < M[u].size(); i++){
v = M[u][i];
if (!indfs[v])//如果v没被处理过
{
Tarjan(v);//dfs(v)
low[u] = min(low[u], low[v]);//u点能到达的最小次序号是它自己能到达点的最小次序号和连接点v能到达点的最小次序号中较小的
}
else if (instack[v])
low[u] = min(low[u], dfn[v]);//如果v在栈内,u点能到达的最小次序号是它自己能到达点的最小次序号和v的次序号中较小的
}
if (dfn[u] == low[u])
{
vector<int> temp;
do
{
v = Stack.top();
Stack.pop();
instack[v] = 0;
temp.push_back(v);
Cell_to_Com[v] = Components.size();
} while (u != v);
Components.push_back(temp);
//cout << temp.size() << " ";
}
//cout << Components.size()<<" "<<v<<endl;
}
2、数组溢出
这种情况在release的模式下也是不报错,同样的是直接闪退,虽然程序并没有运行结束。但是在debug模式下vs2013会提示,而release模式下可以正常运行,甚至可以输出越界的值。
在检查程序未报错闪退的情况时,提供两个可供参考的经验。1、是栈溢出,当然栈溢出的情况很多,可以自行查阅。2、数组溢出在debug下是报错的,release下面是不报错的,很难察觉的到!