¿Cómo sabe free cuánto liberar?


En la programación en C, puede pasar cualquier tipo de puntero que desee como argumento a free, ¿cómo sabe el tamaño de la memoria asignada a free? Cada vez que paso un puntero a alguna función, también tengo que pasar el tamaño (es decir, una matriz de 10 elementos necesita recibir 10 como parámetro para saber el tamaño de la matriz), pero no tengo que pasar el tamaño a la función libre. ¿Por qué no, y puedo utilizar esta misma técnica en mis propias funciones para ahorrarme la necesidad de carrito alrededor de la variable adicional de la longitud de la matriz?

Author: Prashant Kumar, 2009-10-05

11 answers

Cuando se llama a malloc(), se especifica la cantidad de memoria a asignar. La cantidad de memoria realmente utilizada es un poco más que esto, e incluye información adicional que registra (al menos) el tamaño del bloque. No puedes acceder (de manera confiable) a esa otra información - y tampoco deberías: -).

Cuando llamas a free(), simplemente mira la información adicional para averiguar qué tan grande es el bloque.

 284
Author: Gary McGill,
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
2014-06-18 06:32:18

La mayoría de las implementaciones de funciones de asignación de memoria C almacenarán información contable para cada bloque, ya sea en línea o por separado.

Una forma típica (en línea) es asignar tanto un encabezado como la memoria que pidió, rellenada a un tamaño mínimo. Así, por ejemplo, si usted pidió 20 bytes, el sistema puede asignar un bloque de 48 bytes:

  • encabezado de 16 bytes que contiene tamaño, marcador especial, suma de verificación, punteros al bloque siguiente/anterior, etc.
  • 32 área de datos de bytes(sus 20 bytes rellenados a un múltiplo de 16).

La dirección entonces dada a usted es la dirección del área de datos. Luego, cuando libere el bloque, free simplemente tomará la dirección que le dé y, suponiendo que no haya guardado esa dirección o la memoria a su alrededor, verifique la información contable inmediatamente antes de ella. Gráficamente, eso sería a lo largo de las líneas de:

 ____ The allocated block ____
/                             \
+--------+--------------------+
| Header | Your data area ... |
+--------+--------------------+
          ^
          |
          +-- The address you are given

Tenga en cuenta que el tamaño del encabezado y el relleno son totalmente implementados definido (en realidad, todo está definido por la implementación (a) pero la opción de contabilidad en línea es común).

Las sumas de verificación y marcadores especiales que existen en la información contable son a menudo la causa de errores como "Arena de memoria dañada" o "Doble libre" si los sobrescribe o los libera dos veces.

El relleno (para hacer la asignación más eficiente) es la razón por la que a veces puede escribir un poco más allá del final de su espacio solicitado sin causar problemas (aún así, no hagas eso, es un comportamiento indefinido y, solo porque funcione a veces, no significa que esté bien hacerlo).


(a) He escrito implementaciones de malloc en sistemas embebidos donde obtuvo 128 bytes sin importar lo que pidió (ese era el tamaño de la estructura más grande del sistema), asumiendo que pidió 128 bytes o menos (las solicitudes de más se cumplirían con un valor de retorno NULO). Se utilizó una máscara de bits muy simple (es decir, no en línea) para decidir si un fragmento de 128 bytes fue asignado o no.

Otros que he desarrollado tenían diferentes grupos para trozos de 16 bytes, trozos de 64 bytes, trozos de 256 bytes y trozos de 1K, de nuevo usando una máscara de bits para decidir qué bloques se usaron o estaban disponibles.

Ambas opciones lograron reducir la sobrecarga de la información contable y aumentar la velocidad de malloc y free (sin necesidad de fusionar bloques adyacentes al liberar), particularmente importante en el entorno en el que estábamos trabajando.

 115
Author: paxdiablo,
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
2016-02-17 02:00:59

De la lista de preguntas frecuentes comp.lang.c: ¿Cómo sabe free cuántos bytes liberar?

La implementación malloc/free recuerda el tamaño de cada bloque a medida que se asigna, por lo que no es necesario recordarle el tamaño al liberar. (Típicamente, el tamaño se almacena adyacente al bloque asignado, por lo que las cosas generalmente se rompen mal si los límites del bloque asignado se sobrepasan ligeramente)

 43
Author: jdehaan,
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
2009-10-21 10:47:56

Esta respuesta está reubicada desde ¿Cómo sabe free() cuánta memoria hay que desasignar? donde se me impidió rápidamente responder por una aparente pregunta duplicada. Esta respuesta debería ser relevante para este duplicado:


Para el caso de malloc, el asignador de montón almacena una asignación del puntero devuelto original, a los detalles relevantes necesarios para freeing la memoria más tarde. Esto normalmente implica almacenar el tamaño de la región de memoria en cualquier forma relevante para el asignador en uso, por ejemplo, tamaño raw, o un nodo en un árbol binario utilizado para rastrear asignaciones, o un recuento de "unidades" de memoria en uso.

free no fallará si" cambia el nombre " del puntero, o lo duplica de cualquier manera. Sin embargo, no se cuenta la referencia, y solo la primera free será correcta. Los freeadicionales son errores "doble libres".

Intentar freecualquier puntero con un valor diferente a los devueltos por malloc s anteriores, y aún sin liberar es un error. No lo es posible liberar parcialmente regiones de memoria devueltas desde malloc.

 6
Author: Matt Joiner,
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
2017-05-23 12:10:31

En una nota relacionada La biblioteca GLib tiene funciones de asignación de memoria que no guardan el tamaño implícito, y luego simplemente pasa el parámetro size a free. Esto puede eliminar parte de la sobrecarga.

 4
Author: EFraim,
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
2009-10-05 08:07:11

malloc() y free() dependen del sistema/compilador, por lo que es difícil dar una respuesta específica.

Más información sobre esta otra cuestión.

 3
Author: LiraNuna,
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
2017-05-23 12:18:14

El gestor de pilas almacenaba la cantidad de memoria perteneciente al bloque asignado en algún lugar cuando se llamaba malloc.

Yo nunca implementé uno, pero supongo que la memoria justo en frente del bloque asignado podría contener la meta información.

 2
Author: Timbo,
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
2009-10-05 07:48:20

Para responder a la segunda mitad de tu pregunta: sí, puedes, y un patrón bastante común en C es el siguiente:

typedef struct {
    size_t numElements
    int elements[1]; /* but enough space malloced for numElements at runtime */
} IntArray_t;

#define SIZE 10
IntArray_t* myArray = malloc(sizeof(intArray_t) + SIZE * sizeof(int));
myArray->numElements = SIZE;
 1
Author: MSalters,
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
2009-10-05 08:02:53

La técnica original era asignar un bloque ligeramente más grande y almacenar el tamaño al principio, luego darle a la aplicación el resto del blog. El espacio adicional contiene un tamaño y posiblemente enlaza para unir los bloques libres para reutilizarlos.

Sin embargo, hay ciertos problemas con esos trucos, como un comportamiento pobre de la caché y la administración de la memoria. El uso de la memoria en el bloque tiende a las cosas página innecesariamente y también crea páginas sucias que complican el intercambio y copy-on-write.

Así que una técnica más avanzada es mantener un directorio separado. También se han desarrollado enfoques exóticos donde las áreas de la memoria utilizan la misma potencia de dos tamaños.

En general, la respuesta es: se asigna una estructura de datos separada para mantener el estado.

 1
Author: DigitalRoss,
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-05-03 20:38:12

Memoria asignada usando malloc() o calloc() o realloc().

Void free (void *ptr);

La función free no acepta size como parámetro. ¿Cómo sabe la función free () cuánta memoria liberar con solo un puntero?

La siguiente es la forma más común de almacenar el tamaño de la memoria para que free() sepa el tamaño de la memoria a ser desasignada.

Cuando se realiza la asignación de memoria, el espacio real asignado es una palabra mayor que la memoria solicitada. Extra word se usa para almacenar el tamaño de la asignación y luego es usado por free ()

 1
Author: geetha,
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
2016-10-26 07:25:04

Cuando llamamos malloc es simplemente consumir más byte de su requisito. Este consumo de bytes más contiene información como suma de verificación, tamaño y otra información adicional. Cuando llamamos gratis en ese momento directamente ir a esa información adicional donde es encontrar la dirección y también encontrar cuánto bloque será libre.

 0
Author: Varun Chhangani,
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-06-18 16:15:00