我有这个代码,但有一个递归函数,我无法优化它,这就是为什么我总是有StackOverFlow异常。 你能帮我优化一下吗? 我使用此void获取所有信息,或者如果发现一些错误则再次尝试。
public void Parse(byte[] data)
{
Socket skt = new Socket(SocketType.Dgram, ProtocolType.Udp);
skt.ReceiveTimeout = 1000;
skt.Connect(Encryptor.GetNextIP(), port);
skt.Send(data);
try
{
//a lot of actions to get the opcode
switch (opCode)
{
case 0x01:
p = new Packet(opCode);
p.WriteArray(Encryptor.ClientData(answer, false));
Regex rgx = new Regex("\"(?<Name>.+?):");
string part = p.ReadAString();
string res;
if (part[part.Length - 1] != '}') part += '}';
if (rgx.Match(part).Groups["Name"].Value == "")
{
p = null;
Parse(data);
break;
}
else
{ res = "ID=" + rgx.Match(part).Groups["Name"].Value; }
ParseInfo(rgx.Match(part).Groups["Name"].Value);
p = null;
Encryptor = null;
break;
default: string ans = Encoding.ASCII.GetString(recv.Take(bytes).ToArray());
if (ans.Contains("EndOfStream") || ans.Contains("Begin"))
{
Failed();
Encryptor = null;
break;
}
else
{
p = null;
Parse(data);
}
break;
}
}
catch
{
skt.Close();
skt.Dispose();
GC.Collect();
Parse(data);
}
}
提前谢谢。
答案 0 :(得分:1)
您的Try / Catch块正在从代码中捕获异常,然后调用在从执行堆栈弹出异常之前抛出异常的相同函数。这导致了StackOverflowException。
你在一个函数中有一个Try / Catch块,它的Catch段调用包含它的函数。这通常非常危险,并且会隐藏程序的真正例外。出于调试目的,请尝试注释掉try / catch并让调试器向您发出异常,以便您可以获取错误的源站点并跟踪发生的情况。
继续前进,如果您的程序无法处理套接字问题并且绝对不得不抛出异常,请不要尝试将数据推回到函数中。我建议让套接字死掉,清除缓冲区,然后重置连接。然后,您可以将错误记录到文件中,或向用户显示有关失败的消息。
答案 1 :(得分:1)
所有递归函数必须具有并达到终止条件才能回滚堆栈。你忽略了如何导出opCode值,但是如果那个值总是为0x01且regex评估为true,那么函数将永远不会达到终止条件。默认情况下相同,永远不会看到开始或EOS。
另一种看待它的方式是,每次递归调用都必须让你更接近结束。
检查你的代码逻辑,看看为什么你永远不会达到终止条件。
另外,空白捕获假定内存故障,以后再次开始递归也可能有问题...如果socket返回一些通用异常(没有连接),那么你将永远递归(直到堆栈被烧毁)
答案 2 :(得分:1)
您似乎在调用Parse(data)
而没有修改数据内容。有意义的是它会永远地调用它自己,特别是考虑到你的catch块中对Parse(data)
的调用。我没有在你的代码中看到任何会导致递归停止的基本情况。
另外,我真的不建议调用GC.Collect();
让运行时处理内存管理。
答案 3 :(得分:0)
你不能永远地归还,如果你想永远做一些事情,你需要改变你的逻辑“我想要这样做,然后我会一次又一次地调用”到某种形式的同时(真的)这样做在循环中。
因此,将逻辑更改为无限循环,而不是在其中调用Parse,只是不要(因为您的循环将返回到同一位置并且还可以访问数据,所以最终会在同一个位置)< / p>
让我们使用简约示例,而不是重新输入所有代码:
public void Parse(string data)
{
var NewData = data + " again";
Parse("test"); // this will call itself over and over resulting in a stackoverflow exception since the stack has to be preserved for the whole chain of functions
}
将其更改为:
public void Parse(string data)
{
var NewData = data + " again";
while(true)
{
NewData = data + " again"; // Will still run forever but within the same function, no stackoverflow
}
}
我建议您阅读此主题以获取更多信息:What is tail recursion?