我怎样才能捕获递归代码上的 stackoverflow 异常的根源

发布于 2024-09-09 10:20:14 字数 475 浏览 5 评论 0原文

我有以下递归代码,并且收到堆栈溢出异常。我无法找出根本原因,因为一旦出现异常,我就无法在 Visual Studio 中获得完整的调用堆栈。

这个想法是,组织团队可以合并成更大的“主要”团队。

有没有人发现下面这段代码中的缺陷可能是罪魁祸首?

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

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

        return GetUnit(organisationalUnit.Parent);
    }

I have the following recursive code and i am getting a stackoverflow exception. I can't figure out the root cause because once i get the exception,i dont get the full call stack in Visual studio.

The idea is that there are org teams that roll up into larger "Main" teams.

Does anyone see a flaw on this code below that could be the culprit?

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

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

        return GetUnit(organisationalUnit.Parent);
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

掩于岁月 2024-09-16 10:20:14
  1. 您可能有一个单元是其自己的父单元,或者除非您可能有一个父单元循环(例如 ABCA)。也就是说,问题可能出在数据上,而不是代码本身。
  2. 验证 IsMainUnitParent 的 getter 不会调用 GetUnit
  1. You might have a unit which is its own parent, or barring that you might have a cycle of parents (e.g. A-B-C-A). That is, the problem might be with the data, not with the code per se.
  2. Verify that the getters of IsMainUnit and Parent don't call GetUnit.
请恋爱 2024-09-16 10:20:14

根总是有 Parent == null 吗?
尝试检查

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

Does the root always have Parent == null?
Tried checking

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

?

心奴独伤 2024-09-16 10:20:14

你可以尝试这个来更好地调试它。它不会影响您的生产代码。

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;

您可以尝试传递一组以前访问过的节点并检查您之前是否访问过该节点。

递归的问题在于,您必须确保它会结束,而未经检查的循环引用是一种不会结束的情况。

You could try this to debug it better. It won't affect your production code.

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

On second thought...

It's mostlikely that you have a circular reference somewhere.

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

You could try to pass a set of previous visited nodes and check whether or not you've visited this node before.

The thing with recursion is that you have to be sure that it will end and an unchecked circular reference is a situation where it wouldn't end.

鼻尖触碰 2024-09-16 10:20:14

有什么理由不将其重新编码为迭代吗?这样,就可以更轻松地对组织树的深度设置硬性限制,以捕获不良(循环)数据。

递归很有趣,尾部优化甚至可以使其变得高效,但在这里,它看起来就像是解决小问题的大锤子。

Is there any reason not to recode it as an iteration? That way, it'd be easier to set a hard limit on the depth of the organizational tree in order to catch bad (cyclic) data.

Recursion is fun, and tail optimizations can even make it efficient, but here it seems a like large hammer for a small problem.

很酷不放纵 2024-09-16 10:20:14

我对视觉工作室了解不多。
但你应该检查是否复发。例如

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

I don't know much about visual studio.
But you should check for recurrence. e.g.

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);
}
心凉怎暖 2024-09-16 10:20:14

一种方法是减少堆栈大小,这样它就可以尽早崩溃。

您可以通过在程序开始时浪费帧来实现这一点,即获得如下堆栈跟踪:f_n,f_(n-1),...,f_1,waste,waste,.. .,waste,如(在 C 伪代码中)

int wasted = 1;

浪费(int n,无效(* f)())
{ if (n > 0) 浪费(n - 1,f) else f ();
浪费+=1; }

main () { 浪费(N,mainprime);其中

mainprime 是旧的 main,N 足够大以达到您想要的 f_1。

One way to do that would be to reduce the stack size so it can crash earlier on.

You could do that by wasting frames upon the beginning of the program, i.e. to get a stack trace like: f_n,f_(n-1),...,f_1,waste,waste,...,waste, as in (in C pseudo-code)

int wasted = 1;

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

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

where mainprime is your old main, and N is big enough to reach the f_1 you want.

橘香 2024-09-16 10:20:14

代码看起来不错,也许单元树中有一些闭环?尝试添加带有organizationalUnit.GetHashCode值的跟踪行,跟踪输出不受限制,可以帮助检测堆栈溢出原因。

The code looks OK, maybe you have some closed cycles in the Unit tree? Try to add trace lines with organisationalUnit.GetHashCode values, trace output is not limited and can help to detect stack overflow reason.

束缚m 2024-09-16 10:20:14

我想你可以通过重写这个来避免递归,

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

return organisationalUnit;

希望有帮助。

编辑:我刚刚意识到,如果你有某种循环依赖,这仍然会失败。

I guess you could avoid recursion by rewriting this along the lines of

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

return organisationalUnit;

I hope that helps.

EDIT: I just realized this would still fail if you have some sort of cyclic dependency.

表情可笑 2024-09-16 10:20:14

您的图表中可能有一个循环(请注意,它不是一棵树)。

您可以使用这样的代码来检测它:

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

You might have a cycle in your graph (see, it's not a tree).

You can use code like this to detect it:

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);
} 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文