我有这段代码,但是有一个递归函数,我无法优化它,这就是为什么我总是有StackOverFlow异常。你能帮我优化它吗?我使用此空隙来获取所有信息,或者在发现某些错误时重试。
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);
}
}
提前谢谢你。
所有递归函数都必须具有并达到终止条件才能回滚堆栈。 您忽略了 opCode 值是如何派生的,但如果该值总是0x01正则表达式评估为 true,那么函数将永远不会达到终止条件。 默认情况相同,永远不会看到开始或EOS。
另一种看待它的方式是,对于每个递归调用,它必须使您更接近终点。
因此,请检查您的代码逻辑,看看为什么您永远不会达到终止条件。
此外,假设内存错误,后来再次开始递归的空白捕获也可能是错误的......如果套接字返回一些通用异常(无连接),那么您将永远递归(直到堆栈被吹毁)
您似乎在调用Parse(data)
而从未修改过数据的内容。它会永远调用自己是有道理的,特别是考虑到在你的 catch 块中调用Parse(data)
。我在您的代码中没有看到任何会导致递归停止的基本情况。
另外,我真的不建议调用GC.Collect();
让运行时处理内存管理。
您的 Try/Catch 块正在从代码中捕获异常,然后在从执行堆栈中弹出异常之前调用引发异常的同一函数。 这会导致您的 StackOverflowException。
您在函数中有一个 Try/Catch 块,谁的 Catch 段调用包含它的函数。 这通常是非常危险的,并且会隐藏程序的真正异常。 出于调试目的,请尝试注释掉 try/catch 并让调试器向你引发异常,以便您可以获取错误的源站点并跟踪正在发生的事情。
接下来,如果您的程序无法处理套接字问题并且绝对被迫抛出异常,请不要尝试将数据推回函数中。 我建议让套接字死亡,清除缓冲区,然后重置连接。 然后,可以将错误记录到文件中,或向用户显示有关失败的消息。
你不能永远递归,如果你想永远做某事,你需要将你的逻辑从"我想这样做,然后我会一次又一次地调用它"更改为某种形式的 while(true) 循环执行此操作。
因此,将您的逻辑更改为无限循环,而不是在其中调用 Parse,只是不要(您最终会在同一个地方,因为您的循环将回到同一个地方并且还可以访问数据)
让我们用一个简约的例子,而不是重新输入所有代码:
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
}
}
我建议您阅读此线程以获取更多信息:什么是尾递归?