asignación de memoria en Stack y Heap

7 minutos de lectura

asignacion de memoria en Stack y Heap
Samir Baid

Esto puede parecer una pregunta muy básica, pero ha estado en mi cabeza así que:

Cuando asignamos una variable local, entra en la pila. De manera similar, la asignación dinámica hace que la variable se acumule. Ahora, mi pregunta es, ¿esta variable realmente se encuentra en la pila o en el montón o solo haremos una referencia en la pila y en el montón?

Por ejemplo,

Supongamos que declaro una variable int i. Ahora esto i se asigna en la pila. Entonces, cuando imprimo la dirección de i, ¿esta será una de las ubicaciones en la pila? La misma pregunta para el montón también.

  • No entiendo muy bien tu pregunta. Pero puedes leer el libro. Sistemas informáticos: la perspectiva de un programador y sabrás la respuesta.

    – Stan

    21 de julio de 2011 a las 2:22

asignacion de memoria en Stack y Heap
chris eberle

No estoy completamente seguro de lo que estás preguntando, pero haré todo lo posible para responder.

Lo siguiente declara una variable i en la pila:

int i;

Cuando pido una dirección usando &i Obtengo la ubicación real en la pila.

Cuando asigno algo dinámicamente usando mallocen realidad hay DOS piezas de datos que se almacenan. La memoria dinámica se asigna en el montón y el propio puntero se asigna en la pila. Así que en este código:

int* j = malloc(sizeof(int));

Esto es asignar espacio en el montón para un número entero. También está asignando espacio en la pila para un puntero (j). La variable jEl valor de se establece en la dirección devuelta por malloc.

  • Gracias Cris por tu respuesta. Esta era la respuesta que estaba buscando. Entonces, esa es la razón por la que tenemos un problema de programas que se quedan sin pila pero nunca sin HEAP, porque HEAP estaría limitado por la memoria que tiene el sistema.

    – Samir Baid

    21 de julio de 2011 a las 2:20

  • En realidad, la única razón por la que los programas se quedan sin espacio de pila tan rápido es porque es una práctica común poner límites muy pequeños en el espacio de pila (creo que 8 KB es bastante común). Y sí, el montón puede volverse bastante grande si lo dejas.

    – Chris Eberle

    21 de julio de 2011 a las 2:22

  • @Samir No. Tanto la pila como el montón están limitados por la cantidad de memoria del sistema. Los programas se quedan sin pila antes de que se agoten el montón porque el tamaño de la pila suele ser mucho más pequeño que el montón. Sin embargo, los programas aún pueden quedarse sin montón.

    – bola mate

    21 de julio de 2011 a las 2:23

  • @Chris: en Windows, el límite suele ser de 1 MB, no de 8 kB. Supongo que otros sistemas tienen límites similares. Por supuesto, esto es probablemente muy diferente para los sistemas integrados.

    – Rudy Velthuis

    21 de julio de 2011 a las 2:28

  • @Rudy: Pensé que en Windows los límites se compilaban EN el binario y, por lo tanto, dependían del desarrollador. Definitivamente podría creer que 1 MB es el valor predeterminado, 8 KB parece bastante espartano si me preguntas…

    – Chris Eberle

    21 de julio de 2011 a las 2:31


Esperemos que lo siguiente sea útil:

void foo()
{
    // an integer stored on the stack
    int a_stack_integer; 

    // a pointer to integer data, the pointer itself is stored on the stack
    int *a_stack_pointer; 

    // make a_stack_pointer "point" to integer data that's allocated on the heap
    a_stack_pointer = (int*)malloc(10 * sizeof(int));
}

En el caso de las variables de pila, la propia variable (los datos reales) se almacena en la pila.

En el caso de la memoria asignada al montón, los datos subyacentes siempre se almacenan en el montón. Un puntero a esta memoria/datos mayo almacenarse localmente en la pila.

Espero que esto ayude.

  • Esto fue útil, Darren, pero ¿puedes explicarme un caso en el que, en el caso de la memoria asignada en montón, el puntero no se almacene en la pila?

    – Samir Baid

    21 de julio de 2011 a las 2:24

  • @Samir: puede tener una estructura de datos más compleja, donde los datos asignados al montón contienen punteros a otros segmentos de datos asignados al montón. La implementación convencional de una lista enlazada sería un ejemplo de esto, donde cada “nodo” en la lista contiene un puntero al siguiente “nodo” y así sucesivamente.

    – Darren Engwirda

    21 de julio de 2011 a las 2:27

La variable de puntero en sí residiría en la pila. La memoria a la que apunta el puntero reside en el montón.

int *i = malloc(sizeof(int));

i residiría en la pila, la memoria real a la que apunto *i estaría en el montón.

Estoy de acuerdo con Chris. Sólo otra forma de explicar eso. Considere el siguiente código:

int* j = malloc(sizeof(int));
free(j);

Incluso después de usar free(j), que debería desasignar la memoria del montón, el puntero aún existe y debemos convertirlo explícitamente en NULL. Esto definitivamente sugiere que también hay una contraparte de pila del puntero; de lo contrario, debería haber sido inexistente después del comando libre. Esta variable de pila es la que apunta a la dirección en el montón donde la memoria se asignó dinámicamente usando malloc.

La respuesta del Sr. Eberle es 100% correcta, pero dado que Google muestra esto como la primera respuesta cuando busca malloc heap or stacktengo que agregar que malloc() asigna datos en el montón “la mayor parte” del tiempo. Si los datos asignados eran mayores que MMAP_THRESHOLD que suele ser de 128 kb en sistemas de 32 bits, malloc() voluntad no usa el montón y en su lugar asigna los datos en un Segmento de memoria anónimo ubicado generalmente debajo de la pila, creciendo en la dirección de poca memoria.

Esta es la misma región en la que se encuentran las bibliotecas cargadas dinámicamente (libc.so, etc). Aquí está el pasaje relevante de man malloc:

Normalmente, malloc() asigna memoria del montón y ajusta el tamaño del montón según sea necesario, usando sbrk(2). Cuando se asignan bloques de memoria mayores que MMAP_THRESHOLD bytes, la implementación de glibc malloc() asigna la memoria como un mapeo anónimo privado usando mmap(2). MMAP_THRESHOLD es de 128 kB por defecto, pero se puede ajustar usando mallopt(3). Antes de Linux 4.7, las asignaciones realizadas con mmap(2) no se veían afectadas por el límite de recursos RLIMIT_DATA; desde Linux 4.7, este límite también se aplica a las asignaciones realizadas mediante mmap(2).

Como ejemplo práctico, no dudes en consultar el siguiente post. Básicamente asigna 300kb con malloc() y luego corre pmap <PID> para mostrar el segmento de memoria relevante.

  • Bastante seguro MMAP_THRESHOLD no es parte de ANSI/ISO C ni de ningún estándar POSIX. Todavía interesante, pero no una verdad inherente a todas las implementaciones de C. Sin embargo, parece que eso es cierto para glibc y musl.

    – Wyatt Ward

    22 de noviembre de 2019 a las 6:59


1647557408 719 asignacion de memoria en Stack y Heap
anh pham

stack o heap no son memoria separada, son segmentos de memoria que el sistema asigna a un programa en ejecución, solo diferentes formas de organizar los datos en la memoria.

Entonces, cuando obtienes &i, es una dirección de memoria, así de simple.

  • Bastante seguro MMAP_THRESHOLD no es parte de ANSI/ISO C ni de ningún estándar POSIX. Todavía interesante, pero no una verdad inherente a todas las implementaciones de C. Sin embargo, parece que eso es cierto para glibc y musl.

    – Wyatt Ward

    22 de noviembre de 2019 a las 6:59


¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad