Entender la asignación de memoria, fallar progtwig de prueba

Estoy a punto de terminar de leer K&R, y eso es todo lo que sé. Toda mi comstackción se realiza desde la línea de comandos de Windows usando MinGW, y no tengo conocimiento de métodos avanzados de depuración (de ahí el comentario “depuración del ghetto” en mi segundo progtwig a continuación).

Estoy tratando de hacer algunos pequeños progtwigs de prueba para ayudarme a comprender mejor cómo funciona la asignación de memoria. Estos dos primeros progtwigs no usan malloc o gratis, solo quería ver cómo se asigna y se desasigna la memoria para arreglos estándar locales a una función. La idea es que observo el uso de RAM de mis procesos en ejecución para ver si corresponde con lo que entiendo. Para este primer progtwig a continuación, funciona como esperaba. La función alloc_one_meg() asigna e inicializa 250,000 enteros de 4 bytes, pero ese MB se desasigna tan pronto como la función regresa. Por lo tanto, si llamo a esa función 1000000 veces seguidas, nunca debería ver que mi uso de RAM supere 1 MB. Y funciona.

 #include  #include  void alloc_one_meg() { int megabyte[250000]; int i; for (i=0; i<250000; i++) { megabyte[i] = rand(); } } main() { int i; for (i=0; i<1000000; i++) { alloc_one_meg(); } } 

Para este segundo progtwig a continuación, la idea era no permitir que la función salga, tener 1000 copias de la misma función ejecutándose a la vez, lo que logré con la recursión. Mi teoría era que el progtwig consumiría 1 GB de RAM antes de desasignarlo después de que terminara la recursión. Sin embargo, no pasa el segundo ciclo a través de la recursión (vea mi comentario de depuración del ghetto). El progtwig se bloquea con un mensaje bastante no informativo (para mí) (un mensaje emergente de Windows que dice ____. Exe ha encontrado un problema). Por lo general, siempre puedo llegar al fondo de las cosas con mi método de depuración del ghetto … pero no funciona aquí. Estoy perplejo. ¿Cuál es el problema con este código? ¡Gracias!

 #include  #include  int j=0; void alloc_one_meg() { int megabyte[250000]; int i; for (i=0; i<250000; i++) { megabyte[i] = rand(); } j++; printf("Loop %d\n", j); // ghetto debug if (j<1000) { alloc_one_meg(); } } main() { alloc_one_meg(); } 

Pregunta de seguimiento publicada aquí .

Estás corriendo en un desbordamiento de stack.

Las variables de almacenamiento automático local (como megabyte ) se asignan en la stack, que tiene una cantidad limitada de espacio. Malloc asigna en el montón, lo que permite asignaciones mucho más grandes.

Puede leer más aquí:

http://en.wikipedia.org/wiki/Stack_overflow

(Debo tener en cuenta que el lenguaje C no especifica dónde se asigna la memoria; la stack y el montón son detalles de la implementación)

El tamaño de la stack en un progtwig de Windows suele ser de alrededor de 1 MB, por lo que en la segunda recursión, se está desbordando la stack. No debe asignar arrays tan grandes en la stack, use malloc y free para asignar y desasignar la memoria en el montón (no hay manera de sortear malloc para tales tamaños de arrays):

 void alloc_one_meg() { int *megabyte = malloc(sizeof(int) * 250000); // allocate space for 250000 // ints on the heap int i; for (i=0; i<250000; i++) { megabyte[i] = rand(); } j++; printf("Loop %d\n", j); // ghetto debug if (j<1000) { alloc_one_meg(); } free(megabyte); // DO NOT FORGET THIS } 

Dicho esto, realmente puedes cambiar el tamaño de stack de un progtwig y hacerlo más grande (aunque solo lo haría como un ejercicio educativo, no en el código de producción). Para Visual Studio puede usar la opción del comstackdor / F , y en linux puede usar setrlimit(3) . Aunque no estoy seguro de qué usar con MinGW.

La memoria que está asignando a través de las llamadas funcionales recursivas se asigna desde la stack. Toda la memoria de la stack debe ser contigua. Cuando su proceso inicie un hilo, Windows reservará un rango de espacio de direcciones de memoria virtual para la stack de ese hilo. La cantidad de memoria que se debe reservar se especifica en el “encabezado PE” de su archivo EXE. PE significa “ejecutable portátil”.

Usando la utilidad dumpbin incluida con Visual Studio, con él mismo ( dumpbin.exe ) como archivo de entrada:

dumpbin /headers dumpbin.exe

… hay algo de salida, y luego:

  100000 size of stack reserve 2000 size of stack commit 

El “100000” es un número hexadecimal igual a 1.048.576, por lo que esto representa alrededor de 1 MB.

En otras palabras, el sistema operativo solo reservará un rango de direcciones de 1 MB para la stack. Cuando ese rango de direcciones se agota, Windows puede o no puede asignar más rangos de memoria consecutivos para boost la stack. El resultado depende de si hay disponible otro rango de direcciones contiguas. Es muy poco probable que esté disponible, debido a las otras asignaciones que hizo Windows cuando comenzó el hilo.

Para asignar una cantidad máxima de memoria virtual en Windows, use la familia de funciones VirtualAlloc .

Desbordamiento de stack. ¿Es esta una pregunta con trampa?