簡體   English   中英

遞歸函數C#中的StackOverFlow

[英]StackOverFlow in recursive function C#

我有這段代碼,但是有一個遞歸函數,我無法優化它,這就是為什么我總是有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);
        }
    }

先感謝您。

您的Try / Catch塊正在從代碼中捕獲異常,然后調用從異常處理堆棧中彈出該異常的函數。 這導致您的StackOverflowException。

您在函數內有一個Try / Catch塊,誰的Catch段調用包含它的函數。 這通常非常危險,並且會隱藏程序的真正異常。 出於調試目的,請嘗試注釋掉try / catch並讓調試器向您拋出異常,以便您可以獲取錯誤的源站點並跟蹤發生的情況。

展望未來,如果您的程序無法處理套接字問題,並且絕對被迫引發異常,請不要嘗試將數據推回函數中。 我建議讓套接字消失,清除緩沖區,然后重新設置連接。 然后,您可以將錯誤記錄到文件中,或向用戶顯示有關失敗的消息。

所有遞歸函數必須具有並達到終止條件才能回滾堆棧。 您省略了如何導出opCode值,但是如果該值始終為0x01,且正則表達式評估為true,則函數將永遠不會達到終止條件。 默認情況下相同,但從未看到開始或EOS。

另一種看待它的方式是,每次遞歸調用都必須使您更接近最后一步。

因此,請檢查您的代碼邏輯以了解為什么您從未達到終止條件。

同樣,假設內存錯誤並隨后再次開始遞歸的空白catch也可能有錯誤...如果套接字返回一些通用異常(無連接性),則您將永遠遞歸(直到堆棧被炸毀)

您似乎在不修改數據內容的情況下調用了Parse(data) 它將永遠調用自己是有道理的,尤其是考慮到catch塊中對Parse(data)的調用。 我看不到您的代碼中會導致遞歸停止的任何基本情況。

另外,我真的不建議調用GC.Collect(); 讓運行時處理內存管理。

您無法永遠遞歸,如果您想永遠做某事,則需要將邏輯從“我想這樣做,然后我會一遍又一遍地調用”更改為某種形式的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
}
}

我建議您閱讀此線程以獲取更多信息: 什么是尾遞歸?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM