簡體   English   中英

我怎樣才能在遞歸代碼上捕獲stackoverflow異常的根

[英]how can i get catch the root of a stackoverflow exception on recursive code

我有以下遞歸代碼,我得到一個stackoverflow異常。 我無法弄清楚根本原因,因為一旦我得到異常,我在Visual Studio中得不到完整的調用堆棧。

這個想法是有組織團隊加入更大的“主要”團隊。

有沒有人看到下面這段代碼的缺陷可能是罪魁禍首?

    private Unit GetUnit(Unit organisationalUnit)
    {
        if (organisationalUnit.IsMainUnit)
        {
            return organisationalUnit;                
        }

        if (organisationalUnit.Parent == null)
            return null;

        return GetUnit(organisationalUnit.Parent);
    }
  1. 你可能有一個單位是它自己的父母,或者你可能有一個父母的循環(例如ABCA)。 也就是說,問題可能出在數據上,而不是代碼本身。
  2. 驗證IsMainUnitParent的getter是否不調用GetUnit

root總是有Parent == null嗎? 試過檢查

if (organisationalUnit.Parent == organisationalUnit)
    return null;

你可以嘗試這個來更好地調試它。 它不會影響您的生產代碼。

using System.Diagnostics;

private Unit GetUnit(Unit organisationalUnit, int depth)
{
    debug.assert(depth < 10, "Reached an unexpected high recursion depth"); 

    if (organisationalUnit.IsMainUnit)
    {
        return organisationalUnit;                
    }

    if (organisationalUnit.Parent == null)
        return null;

    return GetUnit(organisationalUnit.Parent, depth + 1);
}

private Unit GetUnit(Unit organisationalUnit)
{
    return GetUnit(organisationalUnit.Parent, 0);
}

第二個想法......

最有可能的是你在某處有一個循環引用。

A.parent = B;
B.parent = C;
C.parent = A;

您可以嘗試傳遞一組先前訪問過的節點,並檢查您之前是否訪問過此節點。

遞歸的事情是你必須確保它將結束 ,並且未經檢查的循環引用是不會結束的情況。

有沒有理由不將它重新編碼為迭代? 這樣,為了捕獲不良(循環)數據,更容易對組織樹的深度設置硬限制。

遞歸很有趣,尾部優化甚至可以使它高效,但在這里它看起來像一個小問題的大錘子。

我對視覺工作室了解不多。 但你應該檢查是否復發。 例如

private Unit GetUnit(Unit organisationalUnit)
{
      GetUnit(organisationalUnit, new vector());
}

private Unit GetUnit(Unit organisationalUnit,vector x)
{
    if (organisationalUnit.IsMainUnit)
    {
        return organisationalUnit;                
    }

    if (organisationalUnit.Parent == null)
        return null;

    x.add(this);
    if(x.contains(organisationalUnit.Parent)) throw new Exception("recurrent parent");
    return GetUnit(organisationalUnit.Parent,x);
}

一種方法是減少堆棧大小,以便它可以更早崩潰。

你可以通過在程序開頭浪費幀來實現這一點,即獲得如下的堆棧跟蹤:f_n,f_(n-1),...,f_1,廢物,廢物,......,廢物,如(在C偽代碼中)

int wasted = 1;

waste(int n,void(* f)()){if(n> 0)waste(n - 1,f)else f(); 浪費+ = 1; }

main(){waste(N,mainprime); }

mainprime是你的舊主力,N足夠大到達你想要的f_1。

代碼看起來不錯,也許你在單元樹中有一些封閉的循環? 嘗試使用organisationalUnit.GetHashCode值添加跟蹤線,跟蹤輸出不受限制,可以幫助檢測堆棧溢出原因。

我想你可以通過重寫這一點來避免遞歸

while(organisationalUnit!=null && !organisationalUnit.IsMainUnit)
  organisationalUnit=organisationalUnit.Parent;

return organisationalUnit;

我希望有所幫助。

編輯:我剛剛意識到,如果你有某種循環依賴,這仍然會失敗。

您的圖表中可能有一個循環(請參閱,它不是樹)。

您可以使用這樣的代碼來檢測它:

private Unit GetUnit(Unit organisationalUnit) {
  return GetUnit(organisationalUnit, new HashSet<Unit>());
}

private Unit GetUnit(Unit organisationalUnit, HashSet<Unit> visited) {
  if (visited.Contains(organisationalUnit)) {
    throw new Exception("Cycle detected!"); // or just return null if you prefer
  }
  visited.Add(organisationalUnit);

  if (organisationalUnit.IsMainUnit) {
    return organisationalUnit;
  }

  if (organisationalUnit.Parent == null)
    return null;

  return GetUnit(organisationalUnit.Parent, visited);
} 

暫無
暫無

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

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