此代码,用于匹配NFA中的字符串,我认为需要20,000
内存,当字符串大小为-O2
时,可预测会中断,然后使用-O3
编译代码,然后再次中断为-std=c++14
。编译是在启用"ab"
的情况下完成的。在我看来,问题是堆栈溢出。
输入字符串10,000
重复'c'
次,最后加-O2
。下面的图片包含我尝试匹配的NFA。
具体来说,我的问题是 -
1)这背后的-O3
优化是什么(我相信这是令人印象深刻的)修复?
2)struct State
{
map<char,vector<State*> > transitions;
bool accepting = false;
};
bool match(State* state,string inp){
if(inp=="") return state->accepting;
for(auto s:state->transitions[inp[0]])
if(match(s,inp.substr(1))) return true;
for(auto s:state->transitions['|']) //e-transitions
if(match(s,inp)) return true;
return false;
}
优化会再次破坏它?
{{1}}
在gcc文档中,它说O3具有O2的所有优化,还有更多优化。我无法得到&#34;其中一些额外内容或它们与此问题的相关性。我想强调的是,对于我在类似问题中看到的内容,我并没有找到解决此问题的具体方法。
答案 0 :(得分:2)
正如您已经想到的那样:问题在于递归的堆栈使用。同样,TLO既不会对a[href*="value"] - the attribute value *contains* the specified value
a[href$="value"] - the attribute value *ends with* the specified value
a[href^="value"] - the attribute value *starts with* the specified value
a[href="value"] - the attribute value *matches exactly* the specified value
也不会对-O2
执行(理论上,只有最后一次重复调用才有可能在你的情况下无效)。
但是,根据优化级别,您的功能需要不同的堆栈空间。无法保证-O3
版本更快,并且需要更少的空间。
当我们查看assembly时,我们可以看到以下内容:
-O3
通过-O3
保留88个字节,堆栈上的占用空间更大,因为除了通常的函数序言之外,寄存器subq $88, %rsp
也被压入堆栈。
r12-r15
仅保留56个字节。
如果没有优化,堆栈上的占用空间是最大的:所有内容都需要在两行原始代码之间存储/加载到堆栈中,以便获得可预测的调试行为,以便我们可以在调试器中更改值
这可以解释你的观察结果:没有优化,堆栈很快就会满了。 -O2
优化可以缓解它(但是没有修复它),因此可以处理20000的递归深度 - 它可能会因30000而崩溃。-O2
优化具有更大的堆栈占用空间并且已经失败较小的投入。
现在很明显正确解决了这个问题:应该使用深度优先搜索的迭代版本或广度优先搜索。
代码中的另一个问题 - 使用-O3
会导致不必要的内存复制/使用。只需将迭代器传递给字符串中的第一个字符,然后递增它以进行递归调用。