2011-12-23 14 views
6

Estoy a punto de terminar de leer K & R, y esa es toda la C que conozco. Toda mi compilación se hace desde la línea de comandos de Windows utilizando MinGW, y no tengo conocimiento de los métodos avanzados de depuración (de ahí el comentario "depuración de ghetto" en mi segundo programa a continuación).Descripción de asignación de memoria, programa de prueba fallando

Estoy tratando de hacer algunos pequeños programas de prueba para ayudarme a entender mejor cómo funciona la asignación de memoria. Estos primeros dos programas no usan malloc o libre, solo quería ver cómo se asigna y desasigna la memoria para matrices estándar locales a una función. La idea es que mire el uso de la RAM de los procesos en ejecución para ver si se corresponde con lo que entiendo. Para este primer programa 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 retorna. Entonces, si llamo a esa función 1000000 veces seguidas, nunca debería ver que mi uso de RAM vaya mucho más allá de 1MB. Y funciona.

#include <stdio.h> 
#include <stdlib.h> 

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 programa más adelante, la idea era no permitir que la función para salir, para tener 1000 copias de la misma función en ejecución a la vez, lo que he logrado con la recursividad. Mi teoría era que el programa consumiría 1GB de RAM antes de que se desasignara todo después de que terminara la recursión. Sin embargo, no pasa el segundo ciclo a través de la recursión (ver mi comentario de depuración del gueto). El programa falla con un mensaje bastante no informativo (para mí) (un mensaje emergente de Windows que dice que ____. Exe ha encontrado un problema). Por lo general, siempre puedo llegar al fondo de las cosas con mi método de depuración de guetos ... pero no está funcionando aquí. Estoy perplejo. ¿Cuál es el problema con este código? ¡Gracias!

#include <stdio.h> 
#include <stdlib.h> 

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 publicado here.

+2

Y ahora que tiene un bloqueo de desbordamiento de pila, tiene una mejor comprensión de la memoria. Es curioso cómo las cosas funcionan así. –

+2

Sí, soy nuevo en la programación, pero no soy nuevo en la idea de probar. ¡Soy un ingeniero y un USUARIO de software pesado, y sé muy bien que romper las cosas es la mejor manera de entenderlas! :-) – The111

Respuesta

3

Te encuentras con un desbordamiento de pila.

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

Puede leer más aquí:

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

(Debo señalar que el lenguaje C no especifica donde se asigna la memoria - pila y el montón son detalles de implementación)

+4

Qué bueno, aprendí sobre el desbordamiento de pila en stackoverflow.com. ¡Debería publicar esto en meta! Gracias por la explicación y el enlace. – The111

+0

malloc() no tiene una gran cantidad de espacio: vea la salida del volcado y la cantidad reservada para "montón". –

2

El tamaño de la la pila en un programa de Windows es generalmente de alrededor de 1 MB, por lo que en la segunda recursión, está desbordando la pila. No se le debe asignando dichas matrices grandes en la pila, utilice malloc y free para asignar y desasignar la memoria en el montón (no hay manera de moverse por malloc para tales tamaños de matrices):

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 , puedes cambiar el tamaño de la pila de un programa y hacerlo más grande (aunque solo lo haría como ejercicio educativo, no como código de producción). Para Visual Studio puede use the /F compiler option, y en Linux puede usar setrlimit(3). Aunque no estoy seguro de qué usar con MinGW.

+0

Dijo que no quería usar malloc/free. – Pubby

+2

@Pubby no puede usarlos –

+0

Parte del propósito principal de esta serie de pruebas fue ayudarme a entender el propósito de malloc y gratis. Quería hacer algunas pruebas primero sin ellas, luego unas pocas pruebas con ellas. Sabía que las variables de pila locales tenían una relación de vida con la función entrar/salir, mientras que las variables de pila tenían una vida relacionada con malloc/free, pero no me di cuenta de que la pila tenía un límite tan pequeño. Así que ya aprendí algo importante con esta prueba. :-) – The111

0

StackOverflow. ¿Es esta una pregunta con trampa?

+0

No, soy solo un novato. Estoy aprendiendo muy rápido que hay mucho sobre C que necesito saber que no puedo obtener de K & R (como dije, mi única fuente de conocimiento hasta ahora).¿Dónde hay un buen lugar para aprender sobre el conocimiento que me habría impedido hacer esa pregunta? Stack/Heap, ese tipo de cosas (esos conceptos no están presentes en K & R, y me doy cuenta de por qué). – The111

1

La memoria que está asignando mediante las llamadas funcionales recursivas se asigna desde la pila. Toda la memoria de la pila debe ser contigua.Cuando su proceso inicie un hilo, Windows reservará un rango de espacio de direcciones de memoria virtual para la pila de ese hilo. La cantidad de memoria que se reservará se especifica en el "encabezado PE" del archivo EXE. PE significa "Portable Executable".

Uso de la utilidad dumpbin incluido con Visual Studio, con ella misma (dumpbin.exe) que el archivo de entrada:

dumpbin /headers dumpbin.exe

... hay alguna 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 representa alrededor de 1MB.

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

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