2011-11-17 37 views
25

Duplicar posible:
What and where are the stack and heap¿Por qué la memoria se divide en pila y montón?

tengo un par de preguntas sobre la pila frente montón.

Lo básico es saber que la pila es más rápida que el montón, pero es limitada. (Corrígeme si estoy equivocado).

Sin embargo, siempre me he preguntado cómo funcionan la pila y el montón exactamente. RAM es solo un pedazo de memoria, no está dividido en 'pila' y 'montón' (¿o no?). Si es así, ¿por qué dividimos la memoria en pila y pila en primer lugar?

Los sistemas operativos podrían simplemente permitirnos asignar todo en la pila -> todo va más rápido -> mundo feliz?

Estoy bastante seguro de que ese no es el caso. ¿¡Pero por qué!? ¿Alguien puede darme una respuesta en profundidad?

Disculpa si esta publicación es un duplicado de alguna publicación hecha por alguna persona, hay tantas relacionadas con la pila y el montón, no pude encontrar la pregunta exacta que tenía. Si usted sabe uno, adelante y vincule.

+3

http://stackoverflow.com/questions/7123936/why-is-there-a-stack-and-a-heap – drdwilcox

+2

http://stackoverflow.com/questions/79923/what-and-where-are -the-stack-and-heap –

Respuesta

6

Usted no sólo puede utilizar una pila, ya que una pila requiere un último en entrar, primero en salir el fin de cancelación de asignación asignación & (es decir, sólo se puede anular la planificación de los más nuevos datos asignada; en una pila no se puede anular la planificación de algunos datos antiguos y mantener un poco uno más nuevo).

En realidad, puedes deshacerte de la pila (solo manteniendo el montón). Ver el documento de Appel Garbage Collection Can Be Faster Than Stack Allocation y su libro Compiling with Continuation.

Y el montón no tiene un significado bien definido (que no sea "memoria asignada dinámicamente que no está en la pila"). En realidad, en los sistemas Linux, la asignación de una gran porción de memoria a través de la llamada al sistema mmap es bastante rápida (pero las implementaciones malloc intentan evitar mmap y prefieren reutilizar free -d memoria). El problema es la asignación de zonas de memoria pequeña.

Y lea más acerca de garbage collection techniques. En C o C++ puede usar Boehm's GC

Una pila es a menudo útil, especialmente para llamadas a funciones recursivas. Es tan útil (por ejemplo, en C) que los procesadores de hoy en día generalmente tienen un registro de puntero de pila dedicado (utilizado por CALL & instrucciones de la máquina RET para llamar al & que regresa). Pero éste no siempre fue el caso; en algunos procesadores (por ejemplo, IBM360), el puntero de la pila es un registro convencional, no uno codificado.

+0

información muy útil, gracias :) – xcrypt

0

La memoria es la misma para ambos, pero la pila y el montón son 2 estructuras de datos diferentes que son útiles para diferentes propósitos.

La pila es una abstracción muy primitiva que necesita cualquier microprocesador para ejecutar instrucciones en un par de operandos (generalmente registros de procesador o direcciones de memoria).

El montón es un área de memoria de asignación general donde normalmente desea almacenar datos que no están vinculados a la pila, es decir, su vida útil es mayor que si se almacenan en la pila, o dicho de otra manera, los datos van a ser accesos por diferentes porciones de código.

+0

Bueno, podría asignar algún objeto en la pila en la función principal, y usarlo en todo el programa, no lo necesito para eso. Su argumento podría ser que la pila es limitada, pero una de las cosas que tenía la intención de hacer con mis preguntas era: ¿Por qué la pila es limitada? (por los motivos mencionados anteriormente) – xcrypt

+0

La pila está limitada porque crece desde un extremo de la dirección del espacio de memoria al otro extremo. Si fuera ilimitado, puede corromper la fecha almacenada en el montón cuando se atiende una interrupción (porque la interrupción guarda el estado de la CPU en la pila), por lo que debe establecerse un límite artificial en algún lugar para evitar esto (y eso es porque existe el famoso mensaje 'desbordamiento de pila' cuando alcanzas ese límite). –

23

Pila: La pila se usa como una especie de almohadilla temporal para el bloque de código que se está ejecutando actualmente, y cualquier bloque llamado actual, y cualquier bloque llamado ese, y así sucesivamente. Cuando sale el bloque actual, se olvidan las variables locales que estaba usando. Como su nombre indica, la pila se usa de la última en entrar, primero en salir.

Uno de los usos más importantes de la pila es realizar un seguimiento de la cadena de llamadas actual. Cuando una función llama a otra, la persona que llama empuja la dirección de la siguiente instrucción (la dirección de retorno) a la pila. A medida que cada función sale, aparece la dirección de retorno de la persona que llama fuera de la pila y continúa ejecutando el código comenzando en esa dirección. También se usa para comunicar parámetros de funciones y valores de retorno entre el que llama y el que recibe la llamada.

Montón: El montón es diferente, no tiene un orden particular. Si desea asignar memoria en un bloque de código y hacer que esa memoria permanezca más allá del final del bloque, la asigna al montón. Por supuesto, también necesitará almacenar un puntero/referencia en algún lugar para que otro código pueda encontrar esa memoria; la mayoría de los idiomas proporcionan alojamiento que.

Velocidad: Las diferencias de velocidad no se deben a ninguna propiedad de la memoria en sí misma, como dices en tu pregunta, tanto la pila como el montón suelen habitar en la misma memoria física. Asignar espacio en la pila es rápido debido a la naturaleza LIFO de las pilas: si empujas algo sobre la pila, solo hay un lugar donde puede terminar. Por el contrario, la asignación de un bloque en el montón requiere encontrar una región libre contigua lo suficientemente grande en la memoria. Una asignación de pila puede ser tan rápida como una sola instrucción; una asignación de montón requiere una llamada a una función de asignación de memoria como malloc().

Static v. Dynamic: La asignación de memoria en el montón es dinámica: si se asigna un bloque y el tamaño del bloque, se puede determinar según la entrada que el programa recibe mientras se está ejecutando. Las regiones de memoria asignadas en el montón pueden incluso cambiarse de tamaño si es necesario. Es posible para asignar dinámicamente memoria en la pila, también (consulte la función de biblioteca estándar C alloca()), pero esa memoria se perderá tan pronto como salga la función actual. Las asignaciones de pila generalmente son estáticas: el compilador determina cuánto espacio se necesita para los parámetros (sin registro), los datos de retorno y las variables locales, y genera código para reservar el espacio necesario en la pila cuando se llama a la función.

Ejemplo: Imagine que está creando un procesador de texto. No puede saber con anticipación qué tan grande será el documento, ni cuántos documentos se usarán al mismo tiempo. Al mismo tiempo, desea que los documentos del usuario permanezcan en la memoria siempre que el usuario quiera mantenerlos abiertos. Si intenta asignar memoria para los documentos en la pila, le resultará difícil tener más de uno abierto a la vez, y deberá crear una sola función que cree, edite, guarde y cierre el documento. Asignar el espacio en el montón le permite crear tantos documentos como desee, cada uno de los cuales tiene el tamaño adecuado para los datos que contiene, y para evitar vincular el tiempo de vida de los documentos con el tiempo de vida de una función en particular.

Resumen: En pocas palabras, la pila contiene los valores de las variables (a veces se usan registros en su lugar), mientras que el montón se utiliza para asignar memoria que se utilizará más allá del tiempo de vigencia del bloque actual.

+0

¿Podría darme un ejemplo de algún punto en el que me veo obligado a utilizar el montón? Por ejemplo, podría asignar todo lo que necesito en la pila para todo el programa en la función principal y pasar todo por dirección a las funciones secundarias. EDITAR: ignoremos que la pila está limitada por algo más que la memoria RAM está llena, por el bien de la pregunta. – xcrypt

+0

@xcrypt Eso requeriría que sepa de antemano acerca de cada asignación de memoria que podría realizar su programa. Alternativamente, podría asignar un bloque gigante en su pila desde el cual luego podría asignar dinámicamente la memoria. Ese bloque sería el equivalente funcional de un montón. Agregaré un ejemplo arriba. – Caleb

+0

Mencionaste que el compilador calcula la cantidad de espacio de pila que necesita antes del tiempo de ejecución, ¿verdad? ¿Es eso cierto para el caso de recursión también? Porque si eso es correcto, ¿no debería el compilador ser capaz de solicitar una recursión infinita justo después de compilar el código? – Dubby

Cuestiones relacionadas