2010-10-13 14 views
6

Ok, pregunté la diferencia entre Stackoverflow y bufferoverflow ayer y casi me votaron por el olvido y no obtuve nueva información.¿Cuál es el propósito de cada una de las ubicaciones de memoria, pila, pila, etc.? (perdido en tecnicismos)

Me hizo pensar y decidí reformular mi pregunta con la esperanza de obtener una respuesta que en realidad resuelva mi problema.

Así que aquí va nada.

Conozco cuatro segmentos de memoria (corrígeme si me equivoco). El código, los datos, la pila y el montón. Ahora AFAIK el segmento de código almacena el código, mientras que el segmento de datos almacena los datos relacionados con el programa. ¡Lo que me confunde seriamente es el propósito de la pila y el montón!

Por lo que he entendido, cuando ejecuta una función, todos los datos relacionados a la función se almacenan en la pila y cuando llama de manera recursiva una función dentro de una función, dentro de una función ... Mientras la función es esperando la salida de la función anterior, la función y sus datos necesarios no salen de la pila. Entonces terminas con un desbordamiento de pila. (De nuevo, por favor corrígeme si estoy equivocado)

También sé para qué sirve el montón. Como he leído en otro lugar, es para asignar dinámicamente datos cuando un programa se está ejecutando. Pero esto plantea más preguntas que resuelven mis problemas. ¿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? ¿Dónde se almacenan las matrices? ¿Es que después de que se ejecuta mi código, todo lo que estaba en mi pila se borra? Con todo, por favor cuénteme sobre el montón de una manera más simplificada que solo, es para malloc y alloc porque no estoy seguro de entender completamente cuáles son esos términos.

Espero que las personas que respondan no se pierdan en los detalles técnicos y puedan mantener los términos simples para que un profano los entienda (incluso si el concepto que se describirá no es laico) y continúen educándonos con los términos técnicos como estamos de acuerdo También espero que esta no sea una gran pregunta, ¡porque creo seriamente que no se podrían pedir por separado!

+0

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

Respuesta

6

¿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:

  1. 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.

  2. 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.

+0

Genial ... Realmente me ayuda a entender la gestión de la memoria en detalle ... –

+0

¿Cómo se manejan las variables globales ... ¿No están almacenadas en el segmento de datos? –

+0

Whoa fue una lectura muy larga, pero definitivamente ayuda ... tendrá que pasar por esto un par de veces para que se hunda por completo, ¡pero eso definitivamente responde bastantes preguntas! Volveré con dudas aquí cuando me vengan a la mente :) Gracias. +1 – traumatized

0

En términos de programas C/C++, el segmento de datos almacena variables estáticas (globales), la pila almacena variables locales y el montón almacena variables dinámicamente asignadas (cualquier malloc o new para obtener un puntero). El segmento de código solo almacena el código de máquina (la parte de su programa que ejecuta la CPU).

2

Con respecto a la pila ... Aquí es donde se almacenan los parámetros y las variables locales de las funciones/procedimientos. Para ser más precisos, los parámetros y las variables locales de la función actualmente en ejecución solo se puede acceder desde la pila ... Otras variables que pertenecen a la cadena de funciones que se ejecutaron antes estarán en la pila pero no serán accesibles hasta la función actual completado sus operaciones.

Con respecto a las variables globales, creo que estas se almacenan en el segmento de datos y siempre se puede acceder desde cualquier función dentro del programa creado.

Con respecto a Heap ... Estas son memorias adicionales que pueden asignarse a su programa cuando lo necesite (malloc o nuevo) ... Necesita saber dónde está la memoria asignada en el montón (dirección/puntero) para que pueda acceder a él cuando lo necesite. En caso de que pierda la dirección, la memoria se vuelve accesible, pero los datos aún permanecen allí. Dependiendo de la plataforma y el idioma, este debe ser liberado manualmente por su programa (o se produce una pérdida de memoria) o necesita ser recogido. El montón es comparativamente enorme para apilar y, por lo tanto, se puede usar para almacenar grandes volúmenes de datos (como archivos, flujos, etc.) ...Es por eso que los Objetos/Archivos se crean en Heap y un puntero al objeto/archivo se almacena en la pila.

+0

Gracias esto es byfar la forma más sencilla en que he visto a alguien decirlo :) Por cierto, ¿hay un desbordamiento de montón también? – traumatized

+0

El "desbordamiento de pila" generalmente se denomina "falta de memoria". –

Cuestiones relacionadas