¿Por qué querrías asignar memoria en el montón en lugar de la stack?

Posible duplicado:
¿Cuándo es mejor usar una Pila en lugar de una Pila y viceversa?

He leído algunas de las otras preguntas con respecto a la stack Heap vs, pero parecen enfocarse más en lo que hace la stack / montón en lugar de por qué las usarías.

Me parece que la asignación de stack casi siempre sería la preferida, ya que es más rápida (solo mover el puntero de la stack y buscar espacio libre en el montón), y no es necesario que libere memoria asignada manualmente cuando termine de usarla . La única razón que puedo ver para usar la asignación de montón es si desea crear un objeto en una función y luego usarlo fuera de ese scope de funciones, ya que la memoria asignada de stack se asigna automáticamente después de regresar de la función.

¿Hay otras razones para usar la asignación de heap en lugar de la asignación de la stack que no conozco?

Hay unas pocas razones:

  • El principal es que con la asignación de montón, tiene el control más flexible sobre la vida del objeto (de malloc / calloc a free );
  • El espacio de stack suele ser un recurso más limitado que el espacio de stack, al menos en las configuraciones predeterminadas;
  • Una falla para asignar espacio de montón se puede manejar con gracia, mientras que quedarse sin espacio de stack a menudo es irrecuperable.

Sin la duración flexible del objeto, las estructuras de datos útiles como árboles binarios y listas vinculadas serían prácticamente imposibles de escribir.

  1. Desea una asignación para vivir más allá de una invocación de función
  2. Desea conservar el espacio de stack (que generalmente está limitado a unos pocos MB)
  3. Está trabajando con memoria reubicable (Win16, bases de datos, etc.) o quiere recuperarse de fallas de asignación.
  4. Longitud variable cualquier cosa. Puedes fingir esto, pero tu código será realmente desagradable.

El grande es # 1. Tan pronto como entre en algún tipo de concurrencia o IPC # 1 estará en todas partes. Incluso la mayoría de las aplicaciones de un único subproceso no triviales son difíciles de diseñar sin alguna asignación de montón. Eso prácticamente simulaba un lenguaje funcional en C / C ++.

Entonces quiero hacer una cadena. Puedo hacerlo en el montón o en la stack. Probemos ambos:

 char *heap = malloc(14); if(heap == NULL) { // bad things happened! } strcat(heap, "Hello, world!"); 

Y para la stack:

 char stack[] = "Hello, world!"; 

Así que ahora tengo estas dos cadenas en sus respectivos lugares. Más tarde, quiero hacerlos más largos:

 char *tmp = realloc(heap, 20); if(tmp == NULL) { // bad things happened! } heap = tmp; memmove(heap + 13, heap + 7); memcpy(heap + 7, "cruel ", 6); 

Y para la stack:

 // umm... What? 

Este es solo un beneficio, y otros han mencionado otros beneficios, pero este es bastante bueno. Con el montón, al menos podemos tratar de hacer que nuestro espacio asignado sea más grande. Con la stack, estamos atrapados con lo que tenemos. Si queremos espacio para crecer, tenemos que declararlo todo por adelantado, y todos sabemos cómo apesta ver esto:

 char username[MAX_BUF_SIZE]; 

La razón más obvia para usar el montón es cuando llamas a una función y necesitas que se devuelva algo de longitud desconocida. Algunas veces la persona que llama puede pasar un bloque de memoria y tamaño a la función, pero en otras ocasiones esto no es práctico, especialmente si el material devuelto es complejo (por ejemplo, una colección de objetos diferentes con punteros volando, etc.).

Los límites de tamaño son un gran obstáculo en muchos casos. La stack generalmente se mide en megabytes bajos o incluso kilobytes (eso es para todo en la stack), mientras que todas las PC modernas te permiten unos pocos gigabytes de stack. Entonces, si va a utilizar una gran cantidad de datos, absolutamente necesita el montón.

solo para agregar puede usar alloca para asignar memoria en la stack, pero nuevamente la memoria en la stack es limitada y también el espacio existe solo durante la ejecución de la función solamente. eso no significa que todo debe ser asignado en el montón. como todas las decisiones de diseño, esto también es algo difícil, se debe usar una combinación “juiciosa” de ambos.

Además del control manual de la duración del objeto (que usted mencionó), las otras razones para usar el montón incluirían:

  • Control en tiempo de ejecución sobre el tamaño del objeto (tanto su tamaño inicial como su tamaño “posterior”, durante la ejecución del progtwig).

Por ejemplo, puede asignar una matriz de cierto tamaño, que solo se conoce en tiempo de ejecución.

Con la introducción de VLA (Variable Length Arrays) en C99, fue posible asignar matrices de tamaño de tiempo de ejecución fijo sin usar heap (esto es básicamente una implementación a nivel de lenguaje de la funcionalidad ‘alloca’). Sin embargo, en otros casos, todavía necesitarías un montón incluso en C99.

  • Control en tiempo de ejecución sobre el número total de objetos.

Por ejemplo, cuando construyes una estructura de árbol binario, no puedes asignar los nodos del árbol en la stack de antemano de manera significativa. Debes usar heap para asignarlos “a pedido”.

  • Consideraciones técnicas de bajo nivel, como espacio de stack limitado (otros ya mencionaron eso).

Cuando necesite un gran búfer de E / S, por ejemplo, incluso durante un breve período de tiempo (dentro de una sola función), tiene más sentido solicitarlo del montón en lugar de declarar un conjunto automático grande.

Las variables de stack (a menudo llamadas ‘variables automáticas’) se usan mejor para las cosas que siempre quiere que sean iguales, y siempre son pequeñas.

 int x; char foo[32]; 

Son todas las asignaciones de stack, Estas también se arreglan en tiempo de comstackción.

La mejor razón para la asignación del montón es que no siempre se puede saber cuánto espacio necesita. A menudo solo se sabe esto una vez que el progtwig se está ejecutando. Puede tener una idea de los límites, pero solo desea utilizar la cantidad exacta de espacio requerido.

Si tuviera que leer en un archivo que podría ser cualquier cosa desde 1k hasta 50mb, no haría esto: –

 int readdata ( FILE * f ) { char inputdata[50*1024*1025]; ... return x; } 

Eso trataría de asignar 50mb en la stack, lo que normalmente fallaría ya que la stack generalmente está limitada a 256k de todos modos.

La stack y el montón comparten el mismo espacio de memoria “abierto” y finalmente tendrán que llegar al punto donde se encuentran, si usa todo el segmento de la memoria. Mantener el equilibrio entre el espacio que utiliza cada uno de ellos tendrá un costo amortizado más tarde para la asignación y la desasignación de la memoria un valor asintótico más pequeño.