简体   繁体   中英

StackOverFlow in recursive function C#

I have this code, but there is an recursive function and i can't optimize it, that's why i always have StackOverFlow exception. Can you help me to optimize it? I use this void to get all info or to try again if some errors are found.

 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);
        }
    }

Thank you in advance.

Your Try/Catch block is catching an exception from your code, then calling the same function that throws the exception before it has been popped from the execution stack. This is causing your StackOverflowException.

You have a Try/Catch block within a function, who's Catch segment calls the function containing it. This is generally very dangerous, and will hide the true exception of the program. For debugging purposes, try commenting out the try/catch and letting your debugger raise the exception to you so that you can get the source site of the error and track down what's going on.

Moving forward, if your program cannot handle a problem with the socket and is absolutely forced to throw an exception, don't try to shove the data back into the function. I recommend letting the socket die, clear your buffers, and resetting the connection. Then you can log the error to a file, or show a message to the user about the failure.

All recursive functions must have and reach a terminating condition to rollback the stack. You left out how opCode value is derived, but if that one is ALWAYS 0x01 with regex evaluating to true, then function will never reach terminating condition. Same for default case and never seeing begin or EOS.

Another way of looking at it is that with every recursive call, it must take you one step closer to the end.

So examine your code logic to see why you never reach terminating condition.

also, blank catch that assumes memory fault that later starts recursion again is also possibly at fault... if socket returns some generic exception (no connectivity) then you'll recurse forever (until stack is blown)

You appear to be calling Parse(data) without ever modifying the contents of data. It makes sense that it would call itself forever, especially considering the call to Parse(data) in your catch block. I don't see any base case in your code that would cause the recursion to stop.

Also, I really don't recommend calling GC.Collect(); Let the runtime handle memory management.

You cannot recurse forever, if you want to do something forever you need to change your logic from "i want to do this, and then i'll call this again and again" to some form of while(true) do this in a loop.

So change your logic into an infinite loop and instead of calling Parse within it, just don't (you will end up in the same place since your loop will get back in the same place and also have access to data)

Let's go with a minimalistic example instead of re typing all your code :

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
}

Change it to something like:

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
}
}

I suggest you read this thread for more info : What is tail recursion?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM