递归函数C#中的StackOverFlow

时间:2014-02-25 20:10:26

标签: c# recursion stack-overflow

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

提前谢谢。

4 个答案:

答案 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?