C# Y EL STACK OVERFLOW

28

A los que llevamos ya algunos años trabajando en el mundillo del desarrollo de aplicaciones, términos como heap o stack nos son familiares.

Ahora que están de moda lenguajes de alto nivel como el C# o ActionScript, estos términos suenan difusos, como algo del pasado… y nada más lejos de la realidad.

Los que seáis de mi quinta (rondando la treintena) y tengáis los huevos pelaos de programar, seguro que habéis picado lineas de C y C++ por un tubo. Y como bien sabemos, el stack o pila es un tema que según en que entornos hay que tratar con delicadeza, sobre todo cuando echamos mano de la recursividad.

La recursividad en una poderosa técnica de programación que para los no iniciados, consiste en que una función se llame a si misma. Claros ejemplo de recursividad son el cálculo de un factorial, la serie de Fibonacci o el algoritmo de relleno FloodFill.

Que una función se llame a si misma conlleva un peligro y es que esta se quede llamándose a si misma más de lo esperado, provocando el temido Stack Overflow. En muchos casos, esto es debido a un mal diseño del algoritmo. Pero otras veces no…. necesitamos más memoria para la pila.

Si estamos programando en C o C++, esto no es excesivo problema, ya que en los settings de compilación y linkado podemos especificar memoria «extra» para la pila sin problemas.

El problema está, como en mi caso, si estamos utilizando C#.
¡¡¡No se puede cambiar el tamaño de la pila!!!

En concreto, tanto con el Runtime.NET 1.1 como el 2.0, el stack reservado para una aplicación es de algo menos de 512K’s… una miseria. Un simple algoritmo de floodfill que tuviera que rellenar un área de 512×512 daría sistematicamente un StackOverflow a medio rellenar.

Aquí tenéis un simple fragmento de código en C#:


using System;
using System.Collections.Generic;
using System.Text;

// compilar con: /unsafe

namespace Recurse
{
class Program
{

static unsafe void Main(string[] args)
{
char* fib = stackalloc char[256*256*16];
}
}
}

Este simple programa realiza una reserva de 1024K’s en la pila. Si compilamos y ejecutamos nos dará un StackOverflow.

Después de mucho buscar e investigar, para solucionar el problema tenemos esta solución:

Además del compilador de C#, necesitaremos el Visual C++ 7.0(.net) o superior (desconozco si esto sirve para la versión Express)
Con el Visual C viene una utilidad llamada editbin.exe. Una vez creado nuestro ejecutable (que da error), con esta aplicación le podremos cambiar el tamaño de la pila de la siguiente manera. Desde una consola tecleamos lo siguiente:

editbin /stack:4000000 Programa.exe

Con esta simple linea habremos puesto a disposición de nuestro programa casi 40Mb de Stack, con lo que podremos solucionar el problema.

A mi me ha salvado la vida…. pero no hubiera sido más fácil que microsoft hubiera puesto más settings en sus nuevos compiladores…. se ve que no.

12 Comments

  • Guti
    29 diciembre, 2005 a las 20:12

    Solo confirmar que con el VStudio 2005, también viene la utilidad editbin…

    Si no hubiera sido por tu post, nunca habría sabido ni que existía, ni para que servía.

  • Adolf
    24 abril, 2006 a las 23:34

    Muchas gracias por la ayuda, no sabía como solucionar la excepción del stack overflow. Un saludo desde Tenerife,

    Adolf

  • Polimalo Author
    25 abril, 2006 a las 21:49

    Por eso lo puse aquí, xk yo también las pasé putas con ese problema.

    Saludos.

  • me
    11 marzo, 2008 a las 0:50

    q mamera

  • fransua
    26 abril, 2008 a las 23:49

    a mi no me anda nada.. .nop

  • Polimalo
    28 abril, 2008 a las 19:33

    fransua, si esto no te funciona es muy probable que tengas alguna función recursiva que nunca retorna.

  • Diego
    4 julio, 2008 a las 10:51

    Muchas gracias por la solución. Funciona perfectamente pero me he encontrado con un caso en que no.
    El cambio de tamaño hay que realizarlo sobre el proyecto principal o ejecutable. Resulta que tengo una dll dónde realizo la llamada recursiva. Esa dll la envío a otros usuarios que la usarán en sus proyectos. El problema es que estos usuarios no tendrían por qué cambiar ningún setting de sus proyectos.
    ¿Existe alguna manera de cambiar el tamaño del stack para la dll y así evitar que los usuarios de esa dll tengan que cambiar nada?
    Saludos,
    Diego

  • Mike
    14 agosto, 2008 a las 7:08

    EDITBIN se instala con el Visual Studio en sí, por lo que está disponible aun si sólo instalas VC#.

    Por otro lado el «setting» del stack en VC++ es una opción del linker no del compilador. ¿Porque habria MS de ponerla en el compilador de VC#?

    Saludos.

  • PoliMalo Author
    14 agosto, 2008 a las 22:54

    Diego, lo que comentas de la dll no es posible, ya que el segmento de pila pertenece al ejecutable.

    Mike, buena observación.

  • Guti
    17 agosto, 2008 a las 18:40

    Mike, porque simplemente VC#, no tiene enlazador.

  • Eduardo
    4 junio, 2009 a las 19:12

    Hola, estoy desarrollando una aplicación para el cálculo del polinomio de Tutte en c++. El problema de este algoritmo es que es recursivo y dependiendo de los parámetros de entrada puede llegarse a profundidades que hacen que se sobrepase el umbral soportado.
    Has mencionado algo acerca de que se puede configurar el tamaño de la pila de llamadas para c++, podrías indicarme como hacerlo?
    Un saludo.

  • Ozi
    26 agosto, 2011 a las 18:54

    creo que mi recursividad es muy alta ya que en algunos casos le pongo casi los 100 MB de STACK, gracias por la informacion.