¿Para qué sirve la pila?
Cada programa se compone de funciones/subrutinas/lo que su lenguaje de su elección los llama. Casi siempre, esas funciones tienen algún estado local. Incluso en un bucle for simple, necesitas un lugar donde realizar un seguimiento del contador de bucles, ¿verdad? Eso tiene que ser almacenado en la memoria en alguna parte.
Lo que pasa con las funciones es que la otra cosa que casi siempre hacen es llamar a otras funciones. Esas otras funciones tienen su propio estado local: sus variables locales. No desea que sus variables locales interfieran con los locales de la persona que llama. La otra cosa que tiene que suceder es que, cuando FunctionA llama a FunctionB y luego tiene que hacer otra cosa, quiere que las variables locales en FunctionA permanezcan allí, y tengan sus mismos valores, cuando FunctionB termine.
Mantener el seguimiento de estas variables locales es para qué sirve la pila. Cada llamada de función se realiza configurando lo que se llama marco de la pila. El marco de la pila generalmente incluye la dirección de retorno de la persona que llama (para cuando la función está terminada), los valores de los parámetros de cualquier método y el almacenamiento de cualquier variable local.
Cuando se llama a una segunda función, se crea un nuevo marco de pila, se coloca en la parte superior de la pila y se produce la llamada. La nueva función puede funcionar felizmente en su marco de pila. Cuando esa segunda función retorna, su marco de pila se levanta (se elimina de la pila) y el marco de la persona que llama vuelve a estar en su lugar tal como estaba antes.
Así que esa es la pila. Entonces, ¿cuál es el montón? Tiene un uso similar: un lugar para almacenar datos. Sin embargo, a menudo hay una necesidad de datos que vivan más tiempo que un solo marco de pila. No puede ir a la pila, porque cuando la llamada a la función vuelve, su marco de pila se limpia y se dispara: ahí van sus datos. Entonces lo pones en el montón. El montón es básicamente un pedazo de memoria no estructurado. Solicitas x número de bytes, y lo obtienes, y luego puedes festejarlo. En C/C++, la memoria del montón permanece asignada hasta que desasignar explícitamente. En los lenguajes recogidos de basura (Java/C#/Python/etc.), La memoria de pila se liberará cuando los objetos en ella ya no se usen.
hacer frente a sus preguntas específicas desde arriba:
¿Cuál es la diferencia entre un desbordamiento de pila y un desbordamiento de memoria?
Ambos son casos de sobrepasar un límite de memoria. Un desbordamiento de pila es específico de la pila; has escrito tu código (la recursividad es una causa común, pero no la única), por lo que tiene demasiadas llamadas a funciones anidadas, o estás almacenando muchas cosas grandes en la pila, y se queda sin espacio. La mayoría de los sistemas operativos limitan el tamaño máximo que puede alcanzar la pila, y cuando alcanzas ese límite obtienes el desbordamiento de la pila. El hardware moderno puede detectar desbordamientos de pila y generalmente es malo para su proceso.
Un desbordamiento de búfer es un poco diferente. Entonces primera pregunta: ¿qué es un buffer? Bueno, es un pedazo de memoria limitado. Ese recuerdo podría estar en el montón, o podría estar en la pila. Pero lo importante es que tienes X bytes a los que sabes que tienes acceso. A continuación, escribe un código que escribe X + más bytes en ese espacio. Probablemente el compilador ya haya utilizado el espacio más allá de su memoria intermedia para otras cosas, y al escribir demasiado, ha sobrescrito esas otras cosas. Los desbordamientos de búfer a menudo no se ven de inmediato, ya que no los notará hasta que intente hacer algo con la otra memoria que ha sido destruida.
Además, recuerde cómo mencioné que las direcciones de devolución también se almacenan en la pila. Esta es la fuente de muchos problemas de seguridad debido a los desbordamientos del búfer. Tiene un código que usa un búfer en la pila y tiene una vulnerabilidad de desbordamiento. Un hacker inteligente puede estructurar los datos que desbordan el búfer para sobrescribir esa dirección de retorno, para apuntar al código en el búfer en sí, y así es como obtienen código para ejecutar. Es desagradable.
¿Qué sucede cuando inicialmente inicializo mis variables en el código? ¿Están en el segmento de código o en el segmento de datos o en el montón?
Voy a hablar desde una perspectiva C/C++ aquí. Suponiendo que tiene una declaración de variable:
int i;
Eso reserva (típicamente) cuatro bytes en la pila. Si en su lugar tiene:
char * buffer = malloc (100);
Eso realmente reserva dos trozos de memoria. La llamada a malloc asigna 100 bytes en el montón. Pero también necesita almacenamiento para el puntero, buffer. Ese almacenamiento está, de nuevo, en la pila, y en una máquina de 32 bits será de 4 bytes (la máquina de 64 bits usará 8 bytes).
¿Dónde se almacenan las matrices ... ???
Depende de cómo los declare. Si hace una matriz simple:
char str [128];
por ejemplo, eso reservará 128 bytes en la pila. C nunca golpea el montón a menos que explícitamente se lo pida llamando a un método de asignación como malloc.
Si, por el contrario, declara un puntero (como el búfer anterior), el almacenamiento del puntero está en la pila, los datos reales de la matriz están en el montón.
¿Es que después de que mi código se ejecuta todo lo que estaba en mi montón se borra ... ???
Básicamente, sí. El sistema operativo limpiará la memoria utilizada por un proceso después de que se cierre. El montón es un pedazo de memoria en su proceso, por lo que el sistema operativo lo limpiará. Aunque depende de lo que quiere decir con "limpiarlo". El sistema operativo marca esos trozos de RAM como ahora libres, y los reutilizará más adelante. Si tiene un código de limpieza explícito (como los destructores de C++), deberá asegurarse de que se los llame, el sistema operativo no los llamará por usted.
Con todo, por favor dígame acerca del montón de una manera más simplificada que simplemente, es para malloc y alloc?
El montón es, como su nombre, un montón de bytes libres que puedes tomar de a una por vez, haz lo que quieras y luego vuelve a utilizar para otra cosa. Coges un trozo de bytes llamando a malloc y lo devuelves llamando gratis.
¿Por qué harías esto?Bueno, hay un par de razones comunes:
Usted no sabe cuántos de una cosa que necesite hasta tiempo de ejecución (basado en la entrada del usuario, por ejemplo). Entonces asigna dinámicamente en el montón como los necesita.
Necesita grandes estructuras de datos. En Windows, por ejemplo, la pila de un hilo está limitada de forma predeterminada a 1 meg. Si está trabajando con grandes mapas de bits , por ejemplo, esa será una forma rápida de explotar su pila y obtener un desbordamiento de pila. Así que agarras ese espacio del montón, que generalmente es mucho, mucho más grande que la pila.
El código, datos, pila y el montón?
No era realmente una pregunta, pero quería aclararme. El segmento "código" contiene los bytes ejecutables para su aplicación. Por lo general, los segmentos de código se leen solo en la memoria para ayudar a prevenir la manipulación. El segmento de datos contiene constantes que se compilan en el código: cosas como cadenas de caracteres en su código o inicializadores de matriz deben almacenarse en algún lugar, el segmento de datos es donde van. Nuevamente, el segmento de datos es típicamente de solo lectura.
La pila es una sección escribible de la memoria, y generalmente tiene un tamaño limitado. El sistema operativo inicializará la pila y el código de inicio C llamará a su función main(). El montón también es una sección de escritura de la memoria. Está reservado por el sistema operativo y funciones como malloc y administra de forma gratuita la obtención de fragmentos y su devolución.
Por lo tanto, esa es la visión general. Espero que esto ayude.
posible duplicado de [Qué y dónde están la pila y el montón] (http://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap) – Naveen