¿Asignación/Desasignación de Memoria? [cerrado]


He estado buscando en la asignación de memoria últimamente y estoy un poco confundido acerca de los conceptos básicos. No he sido capaz de envolver mi cabeza alrededor de las cosas simples. ¿Qué significa asignar memoria? ¿Qué pasa? Agradecería respuestas a cualquiera de estas preguntas:

  1. ¿Dónde está la "memoria" que se está asignando?
  2. ¿Qué es esta "memoria"? Espacio en una matriz? O algo más?
  3. ¿Qué sucede exactamente cuando se asigna esta "memoria"?
  4. ¿Qué sucede exactamente cuando la memoria queda desasignada?
  5. También me ayudaría mucho si alguien pudiera responder lo que malloc hace en estas líneas de C++:

    char* x; 
    x = (char*) malloc (8);
    

Gracias.

Author: Adrian Mann, 2013-03-25

4 answers

El Modelo de Memoria

El estándar C++ tiene un modelo de memoria . Intenta modelar la memoria en un sistema informático de una manera genérica. El estándar define que un byte es una unidad de almacenamiento en el modelo de memoria y que la memoria se compone de bytes (§1.7):

La unidad de almacenamiento fundamental en el modelo de memoria C++ es el byte. [...] La memoria disponible para un programa C++ consiste en una o más secuencias de bytes contiguos.

El Objeto Modelo

El estándar siempre proporciona un modelo de objetos . Esto especifica que un objeto es una región de almacenamiento (por lo que se compone de bytes y reside en la memoria) (§1.8):

Las construcciones en un programa C++ crean, destruyen, hacen referencia, acceden y manipulan objetos. Un objeto es una región de almacenamiento.

Así que ahí vamos. La memoria es donde se almacenan los objetos. Para almacenar un objeto en memoria, la región de almacenamiento requerida debe ser asignar.

Funciones de Asignación y Desasignación

El estándar proporciona dos funciones de asignación de alcance global implícitamente declaradas:

void* operator new(std::size_t);
void* operator new[](std::size_t);

Cómo se implementan no es la preocupación de la norma. Todo lo que importa es que deben devolver un puntero a alguna región de almacenamiento con el número de bytes correspondientes al argumento pasado (§3.7.4.1):

La función allocation intenta asignar la cantidad de almacenamiento solicitada. Si lo es con éxito, devolverá la dirección de inicio de un bloque de almacenamiento cuya longitud en bytes será al menos igual al tamaño solicitado. No hay restricciones en el contenido del almacenamiento asignado al retorno de la función de asignación.

También define dos funciones de desasignación correspondientes:

void operator delete(void*);
void operator delete[](void*);

Que se definen para desasignar el almacenamiento que se ha asignado previamente (§3.7.4.2):

Si el argumento dado a un la función de desasignación en la biblioteca estándar es un puntero que no es el valor de puntero nulo (4.10), la función de desasignación desasignará el almacenamiento referenciado por el puntero, haciendo inválidos todos los punteros que se refieran a cualquier parte del almacenamiento desasignado.

new y delete

Normalmente, no debería necesitar usar las funciones de asignación y desasignación directamente porque solo le dan memoria no inicializada. En lugar de eso, en C++ deberías usar new y delete para asignar objetos dinámicamente. Una nueva expresión obtiene almacenamiento para el tipo solicitado usando una de las funciones de asignación anteriores y luego inicializa ese objeto de alguna manera. Por ejemplo, new int() asignará espacio para un objeto int y luego lo inicializará a 0. Véase §5.3.4:

Una nueva expresión obtiene almacenamiento para el objeto llamando a una función de asignación (3.7.4.1).

[...]

Una nueva expresión que crea un objeto de tipo T inicializa ese objeto [...]

En la dirección opuesta, delete llamará al destructor de un objeto (si lo hubiera) y luego desasignará el almacenamiento (§5.3.5):

Si el valor del operando de la delete-expression no es un valor de puntero nulo, la delete-expression invocará el destructor (si lo hubiera) para el objeto o los elementos de la matriz que se están borrando.

[...]

Si el valor del operando de la delete-expressionno es un valor de puntero nulo, la delete-expression llamará a una función de desasignación (3.7.4.2).

Otras asignaciones

Sin embargo, estas no son las únicas formas en que el almacenamiento se asigna o desasigna. Muchas construcciones del lenguaje requieren implícitamente la asignación de almacenamiento. Por ejemplo, dar una definición de objeto, como int a;, también requiere almacenamiento (§7):

Una definición causa la se reservará la cantidad adecuada de almacenamiento y se realizará cualquier inicialización apropiada (8.5).

C biblioteca estándar: malloc y free

Además, el encabezado <cstdlib> trae el contenido de la biblioteca estándar stdlib.h C, que incluye las funciones malloc y free. También están definidas, por el estándar C, para asignar y desasignar memoria, al igual que las funciones de asignación y desasignación definidas por el estándar C++. Aquí está la definición de malloc (C99 §7.20.3.3):

void *malloc(size_t size);
Descripción
La función malloc asigna espacio a un objeto cuyo tamaño está especificado por size y cuyo valor es indeterminado.
Devuelve
La función malloc devuelve un puntero nulo o un puntero al espacio asignado.

Y la definición de free (C99 §7.20.3.2):

void free(void *ptr);
Descripción
La función free causa la espacio señalado por ptr para ser desasignado, es decir, hecho disponible para su posterior asignación. Si ptr es un puntero nulo, no se produce ninguna acción. De lo contrario, si el argumento no coincide con un puntero devuelto anteriormente por el calloc, malloc, o función realloc, o si el espacio ha sido desasignado por una llamada a free o realloc, el comportamiento es indefinido.

Sin embargo, nunca hay una buena excusa para usar malloc y free en C++. Como se describió anteriormente, C++ tiene su propio alternativa.


Respuestas a las preguntas

Así que para responder a sus preguntas directamente: {[42]]}

  1. ¿Dónde está la "memoria" que se está asignando?

    Al estándar C++ no le importa. Simplemente dice que el programa tiene algo de memoria, que se compone de bytes. Esta memoria se puede asignar.

  2. ¿Qué es esta "memoria"? Espacio en una matriz? O algo más?

    En lo que respecta al estándar, la memoria es solo un secuencia de bytes. Esto es intencionalmente muy genérico, ya que el estándar solo trata de modelar los sistemas informáticos típicos. Usted puede, en su mayor parte, pensar en él como un modelo de la memoria RAM de su ordenador.

  3. ¿Qué sucede exactamente cuando se asigna esta "memoria"?

    La asignación de memoria hace que alguna región de almacenamiento esté disponible para su uso por el programa. Los objetos se inicializan en la memoria asignada. Todo lo que necesita saber es que puede asignar memoria. Real la asignación de memoria física a su proceso tiende a ser realizada por el sistema operativo.

  4. ¿Qué sucede exactamente cuando la memoria queda desasignada?

    La desasignación de alguna memoria previamente asignada hace que esa memoria no esté disponible para el programa. Se convierte en almacenamiento desasignado.

  5. También me ayudaría mucho si alguien pudiera responder lo que malloc hace en estas líneas de C++:

    char* x; 
    x = (char*) malloc (8);
    

    Aquí, malloc es simplemente asignar 8 bytes de memoria. El puntero que devuelve está siendo lanzado a char* y almacenado en x.

 56
Author: Joseph Mansfield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-24 22:35:53

1) ¿Dónde está la" memoria " que se está asignando?

Esto es completamente diferente según su sistema operativo, entorno de programación (gcc vs Visual C++ vs Borland C++ vs cualquier otra cosa), computadora, memoria disponible, etc. En general, la memoria se asigna a partir de lo que se llama el montón, región de la memoria a la espera de que usted utilice. Generalmente usará tu RAM disponible. Pero siempre hay excepciones. En su mayor parte, siempre y cuando nos dé memoria, donde viene de no es una gran preocupación. Hay tipos especiales de memoria, como la memoria virtual, que puede o no estar realmente en la RAM en un momento dado y puede moverse a su disco duro (o dispositivo de almacenamiento similar) si se queda sin memoria real. Una explicación completa sería muy largo!

2) ¿Qué es este "recuerdo"? Espacio en una matriz? O algo más?

La memoria es generalmente la RAM en su computadora. Si es útil pensar en la memoria como una gigantesca "matriz", es cierto funciona como uno, entonces piense en ello como una tonelada de bytes (valores de 8 bits, muy parecido a unsigned char valores). Comienza en un índice de 0 en la parte inferior de la memoria. Al igual que antes, sin embargo, hay toneladas de excepciones aquí y algunas partes de la memoria pueden estar mapeadas a hardware, o incluso pueden no existir en absoluto!

3) ¿Qué sucede exactamente cuando esta" memoria " se asigna?

En cualquier momento dado debería haber (¡realmente esperamos!) algunos de ellos disponibles para el software para asignar. Cómo se pone asignado es altamente dependiente del sistema. En general, se asigna una región de memoria, el asignador la marca como utilizada, y luego se le da un puntero para que lo use que le dice al programa en qué parte de la memoria de su sistema se encuentra esa memoria. En su ejemplo, el programa encontrará un bloque consecutivo de 8 bytes (char) y devolverá un puntero a donde encontró ese bloque después de que lo marque como "en uso".

4) ¿Qué sucede exactamente cuando la memoria se desasigna?

El el sistema marca esa memoria como disponible para su uso de nuevo. Esto es increíblemente complicado porque esto a menudo causará agujeros en la memoria. Asigne 8 bytes y luego 8 bytes más, luego desasigne los primeros 8 bytes y tendrá un agujero. Hay libros enteros escritos sobre el manejo de la desasignación, la asignación de memoria, etc. Esperemos que la respuesta corta será suficiente!

5) También me ayudaría mucho si alguien pudiera responder lo que malloc hace en estas líneas de C++:

REALMENTE crudamente, y suponiendo que está en una función (por cierto, nunca hagas esto porque no desasigne tu memoria y causa una fuga de memoria):

void mysample() {
  char *x; // 1
  x = (char *) malloc(8); // 2
}

1) Este es un puntero reservado en el espacio local de la pila. No ha sido inicializado por lo que apunta a lo que ese pedazo de memoria tenía en él.

2) Llama a malloc con un parámetro de 8. El cast solo permite que C / C++ sepa que tiene la intención de que sea un (char *) porque devuelve un (void *) lo que significa que no tiene ningún tipo aplicado. Entonces el puntero resultante es almacenado en su variable x.

En un ensamblaje de 32 bits x86 muy crudo, esto se verá vagamente como

PROC mysample:
  ; char *x;
  x = DWord Ptr [ebp - 4]
  enter 4, 0   ; Enter and preserve 4 bytes for use with 

  ; x = (char *) malloc(8);
  push 8       ; We're using 8 for Malloc
  call malloc  ; Call malloc to do it's thing
  sub esp, 4   ; Correct the stack
  mov x, eax   ; Store the return value, which is in EAX, into x

  leave
  ret

La asignación efectiva se describe vagamente en el punto 3. Malloc generalmente solo llama a una función del sistema para esto que maneja todo el resto, y como todo lo demás aquí, es muy diferente de un sistema a otro, de un sistema a otro, etc.

 11
Author: Mark Ormston,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-24 22:07:15

1 . ¿Dónde está la" memoria " que se está asignando?

Desde la perspectiva del lenguaje, esto no está especificado, y principalmente porque los detalles finos a menudo no importan. Además, el estándar C++ tiende a errar por el lado de no especificar los detalles del hardware, para minimizar las restricciones innecesarias (tanto en las plataformas en las que se pueden ejecutar los compiladores como en las posibles optimizaciones).

La respuesta de Sftrabbit da una gran visión general de este fin de las cosas (y es todo lo que realmente necesidad), pero puedo dar un par de ejemplos trabajados en caso de que ayude.

Ejemplo 1:

En una computadora de un solo usuario suficientemente antigua (o una incrustada suficientemente pequeña), la mayor parte de la RAM física puede estar directamente disponible para su programa. En este escenario, llamar a malloc o new es esencialmente una contabilidad interna, lo que permite a la biblioteca de tiempo de ejecución rastrear qué trozos de esa RAM están actualmente en uso. Puedes hacer esto manualmente, pero se vuelve bastante tedioso pronto.

Ejemplo 2:

En un sistema operativo multitarea moderno, la RAM física se comparte con muchos procesos y otras tareas, incluidos los subprocesos del núcleo. También se utiliza para el almacenamiento en caché de disco y el almacenamiento en búfer de E/S en segundo plano, y se ve aumentada por el subsistema de memoria virtual que puede intercambiar datos al disco (o a algún otro dispositivo de almacenamiento) cuando no se están utilizando.

En este escenario, llamar a new primero puede verificar si su proceso ya tiene suficiente espacio libre internamente, y solicitar más del sistema operativo si no. Cualquier memoria que se devuelva puede ser física, o puede ser virtual(en cuyo caso la RAM física no se puede asignar para almacenarla hasta que realmente se acceda). Ni siquiera puede notar la diferencia, al menos sin usar API específicas de la plataforma, porque el hardware de memoria y el núcleo conspiran para ocultárselo.

2 . ¿Qué es este "recuerdo"? Espacio en una matriz? O algo más?

En el ejemplo 1, es algo como espacio en una matriz: la dirección devuelta identifica un fragmento direccionable de RAM física. Incluso aquí, las direcciones RAM no son necesariamente planas o contiguas-algunas direcciones pueden estar reservadas para ROM, o para puertos de E / S.

En el ejemplo 2, es un índice en algo más virtual: el espacio de direcciones de su proceso. Esta es una abstracción utilizada para ocultar los detalles subyacentes de la memoria virtual de su proceso. Cuando accede a esta dirección, el hardware de memoria puede acceder directamente a alguna RAM real, o es posible que deba pedirle al subsistema de memoria virtual que proporcione algunos.

3 . ¿Qué sucede exactamente cuando esta" memoria " se asigna?

En general, se devuelve un puntero que puede usar para almacenar tantos bytes como haya pedido. En ambos casos, malloc o el operador new hará un poco de limpieza para rastrear qué partes del espacio de direcciones de su proceso se utilizan y cuáles son libres.

4 . ¿Qué sucede exactamente cuando la memoria se desasigna?

De nuevo en general, free o delete harán algunas tareas domésticas para que sepan que la memoria está disponible para ser reasignada.

También me ayudaría mucho si alguien pudiera responder lo que malloc hace en estas líneas de C++: {[19]]}

char* x; 
x = (char*) malloc (8);

Devuelve un puntero que es NULL (si no pudo encontrar los 8 bytes que desea), o algún valor no NULO.

Las únicas cosas que puedes decir útilmente sobre este valor no NULO son que: {[19]]}

  • es legal (y seguro) para acceder a cada uno de esos 8 bytes x[0]..x[7],
  • es ilegal (comportamiento indefinido) acceder a x[-1] o x[8] o en realidad cualquier x[i] a menos que 0 <= i <= 7
  • es legal comparar cualquiera de x, x+1, ..., x+8 (aunque no puedes desreferenciar el último de esos)
  • si su plataforma/hardware / lo que sea tiene restricciones sobre dónde puede almacenar datos en memoria, entonces x los cumple
 7
Author: Useless,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-24 22:31:36

Asignar memoria significa pedir memoria al sistema operativo. Significa que es el propio programa el que pide "espacio" en RAM cuando solo lo necesita. Por ejemplo, si desea utilizar una matriz pero no sabe su tamaño antes de que se ejecute el programa, puede hacer dos cosas: - declare and array[x] with x dediced by you, arbitrary long. Por ejemplo, 100. Pero, ¿qué pasa si su programa solo necesita una matriz de 20 elementos? Estás desperdiciando la memoria para nada. - entonces usted programa puede malloc un matriz de elementos x justo cuando conoce el tamaño correcto de x. Los programas en memoria se dividen en 4 segmentos: - pila (necesario para llamar a las funciones) - code (el código ejecutable de bibary) - datos (variables globales/datos) - heap, en este segmento se encuentra la memoria asignada. Cuando decide que ya no necesita la memoria asignada, la devuelve al sistema operativo.

Si desea asignar y matriz de 10 enteros, lo hace:

Int * array = (int *)malloc (sizeof (int) * 10)

Y luego lo devuelves al sistema operativo con libre (matriz)

 3
Author: user2204592,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-24 21:59:59