递归函数 C# 中的 StackOverFlow



我有这段代码,但是有一个递归函数,我无法优化它,这就是为什么我总是有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
}
}

我建议您阅读此线程以获取更多信息:什么是尾递归?

最新更新