[英]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.