2010-07-13 17 views
6

Tengo el siguiente código recursivo y estoy obteniendo una excepción de stackoverflow. No puedo entender la causa raíz porque una vez que obtengo la excepción, no obtengo la pila completa de llamadas en Visual Studio.cómo puedo obtener la raíz de una excepción de stackoverflow en el código recursivo

La idea es que hay equipos de organización que se agrupan en equipos "principales" más grandes.

¿Alguien ve un error en este código a continuación que podría ser el culpable?

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

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

     return GetUnit(organisationalUnit.Parent); 
    } 

Respuesta

4

¿La raíz siempre tiene Parent == null? Comprobación probada

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

?

+0

por lo que fue un problema de datos que el padre de una unidad se configuró como sí mismo, pero la sugerencia de código para verificar esto solucionó mi problema. . – leora

+0

@ooo Me alegro. Los errores se repiten. Como la historia :-) – Mau

+0

Esto no atrapará todos los casos, algunos ciclos pueden ir más profundo, como cuando una 'Unidad' es su propio abuelo. –

1

¿Hay alguna razón para no recodificarlo como una iteración? De esta forma, sería más fácil establecer un límite estricto en la profundidad del árbol de la organización para capturar datos malos (cíclicos).

La recursividad es divertida, y las optimizaciones de la cola pueden incluso hacerlo eficiente, pero aquí parece un martillo grande para un pequeño problema.

+0

En este caso, el problema parece que puede estar con los datos. –

+0

De hecho. Pero con una solución iterativa, podría verificar más fácilmente ciclos más largos (por ejemplo, agregando explícitamente nodos ya encontrados a una lista o conjunto). –

5
  1. Es posible que tenga una unidad que sea su propia controladora o que impida que tenga un ciclo de padres (por ejemplo, A-B-C-A). Es decir, el problema podría ser con los datos, no con el código per se.
  2. Compruebe que los captadores de IsMainUnit y Parent no llamen al GetUnit.
1

No sé mucho sobre visual studio. Pero debe verificar la recurrencia. p.ej.

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

El código se ve bien, ¿quizás tiene algunos ciclos cerrados en el árbol de unidades? Intente agregar líneas de rastreo con valores organisationalUnit.GetHashCode, la salida de rastreo no está limitada y puede ayudar a detectar el motivo de desbordamiento de la pila.

0

Creo que se puede evitar la repetición reescribiendo este a lo largo de las líneas de

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

return organisationalUnit; 

espero que ayude.

EDIT: Me acabo de dar cuenta de que esto aún fallaría si tuviera algún tipo de dependencia cíclica.

1

Una forma de hacerlo sería reducir el tamaño de la pila para que pueda colgarse antes.

Se podría hacer que al perder marcos en el inicio del programa, es decir, para obtener un seguimiento de pila como: f_n, F_ (n-1), ..., f_1, desechos, residuos, ..., waste, como en (en pseudocódigo C)

int wasted = 1;

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

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

donde mainprime es su principal anterior, y N es lo suficientemente grande como para alcanzar el valor de f_1 que desea.

2

Puede intentar esto para depurarlo mejor. No afectará su código de producción.

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

Pensándolo bien ...

Es mostlikely que tiene una referencia circular en alguna parte.

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

Puede intentar pasar un conjunto de nodos visitados anteriormente y comprobar si ya ha visitado este nodo anteriormente.

La cosa con recursividad es que tiene que estar seguro de que va a terminar y una referencia circular sin control es una situación en la que no terminaría.

0

Puede tener un ciclo en su gráfico (consulte, no es un árbol).

Puede utilizar código como este para detectarlo:

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