¿Por qué se utilizan montones para la asignación de memoria? ¿Por qué no se utilizan pilas ni ninguna otra?

Esta es una gran pregunta. Las cuatro respuestas ante mí parecen sugerir que estás confundiendo “montón, la estructura de datos” con “montón, la región de la memoria”. No lo creo. Por lo tanto, voy a tratar de responder su pregunta, suponiendo que su pregunta sea “¿por qué necesitamos tanto el montón como la pila? ¿Por qué no se puede hacer todo solo con la pila?” Si esa no fue la intención de su pregunta, hágamelo saber para que pueda eliminar esta respuesta.

Ahora, para la respuesta real: ¿por qué apilar Y apilar?

Lo más importante que debemos entender aquí es que la funcionalidad de la pila es muy diferente de la del montón.

En un lenguaje de programación típico, se crea un “marco de pila” cuando se llama a una función. De ahora en adelante, todas las variables locales de esa función se crean dentro de los límites de este marco de pila. Luego, cuando la función regresa, su marco de pila se “borra”. Darse cuenta de que todo esto es “automágico”. El programador de ese lenguaje de programación de alto nivel NO tuvo que crear el marco de la pila cuando se llamó a la función, no colocó variables locales en él cuando se crearon / usaron, y no eliminó el marco de la pila cuando la función regresó. El sistema de tiempo de ejecución subyacente proporcionó toda esa funcionalidad.

Pero, fundamentalmente, parece haber un gran programa con la pila: las cosas surgen en el marco de la pila, ¡PERO luego desaparecen cuando vuelve la función! Entonces, si quisiera tener una variable que fuera accesible desde múltiples funciones, entonces, la pila parece ser un mal lugar para crearla.

Por lo tanto, necesitamos un lugar donde podamos crear variables que puedan existir llamadas de función “ENTRE / ACROBADAS”. Obviamente, esto tendrá que estar fuera de la pila. ¿Cómo podemos llamar a este “montón de memoria” donde los datos están esparcidos por todo el lugar? Hmm! Digamos que es un montón, o eso parece haber decidido nuestra gente mayor.

Otro hecho muy importante aquí es que puede asignar “todo lo que quiera” en el montón. Si hay espacio en el montón, entonces la asignación tendrá éxito. Por otro lado, cualquier cosa que haya asignado en el montón se puede liberar en cualquier momento. La pila no te da la libertad de “liberar objetos en la pila” porque eso podría estropear la pila.

Es simplemente “coincidente” que la pila se implementa “exactamente” como la “pila denominada estructurada de datos”, pero el montón no tiene una relación real con la “estructura de datos denominada montón”. En este caso, creo que necesitamos ver el “montón” como eso: un montón de memoria … es decir, una región de memoria grande y desorganizada donde podemos colocar cosas (como en datos, de cualquier tamaño) y eliminar cosas de .

HTH!

No confunda el montón de estructura de datos (como en Heap Sorting, por ejemplo) con el término ‘montón’ usado en el contexto de la asignación dinámica de memoria.

La memoria estática (no dinámica) que existe se llama pila . Cada función (y subprocesos) tiene su propio espacio de pila que está asignado estáticamente en tiempo de compilación. El compilador (basado en los indicadores de optimización y otros “conocimientos”) asigna un espacio de pila fijo para cada función que tenga en el programa.

La razón (creo) por la que esto se llama montón es porque crece . En la mayoría de las arquitecturas de computadora (como x86), e históricamente, el diseño de la memoria de un proceso (supongamos que los archivos binarios de formato ejecutable y de enlace (ELF) se ve así:

Como puede ver, la pila crece y el montón crece (más como un montón / montón de nieve). Solo mi salvaje conjetura

(Fuente de la imagen: 15-412 notas de clase)

Tenía la misma duda cuando comencé con las estructuras de datos …

Verá que la memoria principal se divide en tres secciones:

  1. Montón
  2. Apilar
  3. Sección de código

Ahora, el montón y la pila en la memoria principal son diferentes de las “estructuras de datos lógicos”: ¡montón, pila!

Toda la asignación de memoria estática se realiza en la sección de código;
Si bien toda la asignación de memoria dinámica se realiza en la pila y el montón de la memoria principal.

Dinámico en el sentido de que el tamaño y el tipo de variable se pueden declarar durante el tiempo de ejecución.
Esto se puede hacer utilizando el operador ‘malloc’ en C y el operador ‘nuevo’ en C ++.

Otra cosa a tener en cuenta es que un programa no puede acceder directamente a la sección del montón; Los “punteros” se utilizan para acceder a la sección del montón.

La pila es una forma muy rápida de asignar memoria, la única desventaja es que los fragmentos de memoria deben desasignarse en el orden inverso exacto en que fueron asignados. Esto significa que la pila siempre es contigua y no tiene “agujeros”

Esto es perfecto para llamadas a funciones anidadas o recursivas: cada invocación de función asigna memoria para sus variables locales y luego la desasigna cuando regresa.

La asignación y la desasignación en la pila es extremadamente fácil: simplemente incremente o disminuya el puntero de la pila … No puedes tener nada más rápido.

Sin embargo, a veces necesita asignar cosas y luego desasignarlas en un orden diferente, por ejemplo, en una estructura de datos dinámica como una lista o un árbol, en ese caso, el montón es la única opción. Puede asignar cualquier fragmento y desasignarlo cuando lo coloque. Un montón de memoria puede tener “agujeros”

También, por lo general, el tamaño de las pilas es limitado y crece hacia abajo, pero el sistema operativo administra el almacenamiento dinámico y crece hacia arriba para llenar toda la cuota de memoria del proceso o toda la memoria virtual.

Hay una diferencia entre el montón de estructura de datos y el montón usado para la asignación de memoria.

Los montones se utilizan en lenguajes de programación para la asignación de memoria. Los valores asignados en un montón se almacenan permanentemente y el usuario debe eliminarlos manualmente. Los valores en la pila, por otro lado, se eliminarán automáticamente una vez que finalice la llamada a la función.

La razón para el uso del montón es que son de tamaño variable. Si no está seguro del tamaño del código de su programa, es decir, cuánto espacio ocupará, es mejor usar Heap. Las pilas tienen un tamaño fijo y pueden causar problemas de desbordamiento de pila, es decir, si su código requiere demasiada memoria, tendrá problemas con el uso de la pila.

En general, las pilas son más rápidas que las pilas.

Te estás confundiendo un poco. La porción de memoria utilizada para la asignación de memoria dinámica se denomina simplemente “montón”. No tiene relación con el montón de estructura de datos. Es solo una coincidencia que se les llame lo mismo.

La memoria utilizada para la asignación de memoria dinámica se llama montón, no al revés. Parece que estás confundido entre el montón de memoria y el montón de estructura de datos.

También hay dos pilas: una es la estructura de datos de la pila y la otra es el segmento de la pila, que es uno de los tres segmentos de memoria organizados cuando un programa se carga en la memoria.