¿Cómo sabe gratis cuánto liberar?

9 minutos de lectura

avatar de usuario
Josué mejilla

En la programación C, puede pasar cualquier tipo de puntero que desee como argumento para liberar, ¿cómo sabe el tamaño de la memoria asignada para liberar? 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 al función libre. ¿Por qué no, y puedo usar esta misma técnica en mis propias funciones para evitar tener que cargar con la variable adicional de la longitud de la matriz?

  • Una pregunta similar: stackoverflow.com/questions/851958/… (aunque diría que no es del todo duplicado)

    – John Carter

    5 de octubre de 2009 a las 11:34

  • Él sistema de amigos es otra forma de hacerlo que se puede calcular en función del puntero, sin sobrecarga en cada bloque.

    – EvilTeach

    9 de marzo de 2014 a las 16:34


  • Esta publicación lo explica bien: stackoverflow.com/questions/1957099/…

    – Zeeshan

    2 de diciembre de 2016 a las 7:23

avatar de usuario
gary mcgill

Cuando usted llama malloc(), especifique la cantidad de memoria que se asignará. La cantidad de memoria realmente utilizada es un poco más que esto e incluye información adicional que registra (al menos) qué tan grande es el bloque. No puede (confiablemente) acceder a esa otra información, y tampoco debería hacerlo :-).

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

  • FYI, por ejemplo BSD tiene malloc_size() para acceder de forma fiable al tamaño del bloque desde un malloc()puntero ed. Pero no hay una manera confiable y portátil.

    – laalto

    5 de octubre de 2009 a las 7:53

  • Creo que es importante decir que este bloque de información adicional se encuentra antes del puntero devuelto.

    – Georg Scholly

    5 de octubre de 2009 a las 8:28

  • @gs Bueno, eso depende de la implementación. Pero, sí, ahí es donde suele estar.

    – Falaína

    5 de octubre de 2009 a las 11:20

  • ¿Te imaginas el horror si free() requirió que el programador informara con precisión qué tan grande es el malloc() bloque fue? Las fugas de memoria ya son bastante malas.

    – MusiGénesis

    7 de abril de 2010 a las 13:45

  • ¿Por qué esa información está disponible para malloc() y free(), pero tienes que almacenar el tamaño de una matriz? ¿Por qué no harían posible hacer algo como blockSize(ptr) si están almacenando la información de todos modos?

    – CorsiKa

    14 de junio de 2014 a las 1:12

avatar de usuario
paxdiablo

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

Una forma típica (en línea) es asignar un encabezado y la memoria que solicitó, rellenada hasta un tamaño mínimo. Entonces, por ejemplo, si solicitó 20 bytes, el sistema puede asignar un bloque de 48 bytes:

  • Encabezado de 16 bytes que contiene tamaño, marcador especial, suma de comprobación, punteros al bloque siguiente/anterior, etc.
  • Área de datos de 32 bytes (sus 20 bytes se completaron a un múltiplo de 16).

La dirección que se le proporciona es la dirección del área de datos. Luego, cuando liberes el bloque, free simplemente tomará la dirección que le das y, suponiendo que no hayas rellenado esa dirección o la memoria que la rodea, verificará la información contable inmediatamente anterior. Gráficamente, eso estaría en la línea 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 están totalmente definidos por la implementación (en realidad, todo está definido por la implementación) (un) pero la opción de contabilidad en línea es común).

Las sumas de verificación y los marcadores especiales que existen en la información contable suelen ser la causa de errores como “Memoria dañada” o “Doble liberación” si los sobrescribe o los libera dos veces.

El relleno (para hacer que la asignación sea 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 lo haga, es un comportamiento indefinido y, solo porque funciona a veces, no no significa que está bien hacerlo).


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

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

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

  • @paxdiablo ¿Eso significa que malloc no asigna bloques de memoria contiguos?

    – usuario10678

    5 de noviembre de 2017 a las 8:20

  • @user10678, el único requisito real de malloc es que te dé, para el caso exitoso, un bloque de memoria al menos tan grande como lo que pediste. Los bloques individuales son contiguos en términos de cómo accedes a los elementos dentro de ellos, pero no hay ningún requisito de que las arenas de las que provienen los bloques sean contiguas.

    – pax diablo

    5 de noviembre de 2017 a las 8:29

  • Pregunta relacionada: ¿Por qué no hay variación de malloc/free, donde especifica el tamaño al liberar y así no tiene que almacenar el tamaño?

    – usuario253751

    4 de diciembre de 2019 a las 14:57

  • @ usuario253751, porque entonces hay uno más cosa que necesita para realizar un seguimiento, más allá del puntero en sí. ambos son innecesarios y peligroso: void *x = malloc(200); free(x, 500); es no va a terminar bien 🙂 En cualquier caso, por eficiencia, el actual el tamaño del búfer puede ser mayor (simplemente no puede confiar en esto).

    – pax diablo

    5 de diciembre de 2019 a las 2:30


  • @paxdiablo También evita desperdiciar memoria para mantener el tamaño.

    – usuario253751

    5 de diciembre de 2019 a las 10:15

avatar de usuario
carpintero mate

Esta respuesta se reubica de ¿Cómo sabe free() cuánta memoria desasignar? donde se me impidió de manera abrupta responder por una pregunta aparentemente duplicada. Esta respuesta entonces debería ser relevante para este duplicado:


para el caso de mallocel asignador de montón almacena una asignación del puntero devuelto original, a los detalles relevantes necesarios para freeing la memoria más tarde. Por lo general, esto implica almacenar el tamaño de la región de memoria en cualquier forma relevante para el asignador en uso, por ejemplo, tamaño sin formato, o un nodo en un árbol binario utilizado para realizar un seguimiento de las asignaciones, o un recuento de “unidades” de memoria en uso.

free no fallará si “cambia el nombre” del puntero o lo duplica de alguna manera. Sin embargo, no se cuenta la referencia, y solo la primera free será correcto. Adicional frees son errores “doble gratis”.

Intentando free cualquier puntero con un valor diferente a los devueltos por anteriores mallocs, y aún no liberado es un error. No es posible liberar parcialmente regiones de memoria devueltas malloc.

  • Cambié el valor de un puntero devuelto por una llamada malloc. Y lo liberé sin error. ¿Por qué? Ver aquí: stackoverflow.com/questions/42618390/…

    – smwikipedia

    6 de marzo de 2017 a las 6:03

El administrador del montón almacenó la cantidad de memoria que pertenece al bloque asignado en algún lugar cuando llamó malloc.

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

avatar de usuario
jdehaan

Desde el comp.lang.c Lista de preguntas frecuentes: ¿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. (Normalmente, el tamaño se almacena junto al bloque asignado, razón por la cual las cosas suelen romperse mal si los límites del bloque asignado se superan aunque sea un poco)

  • Esta es una no respuesta. La pregunta es exactamente esta: ¿por qué Free puede buscar de manera confiable el tamaño del bloque, pero aún así no hay ninguna función disponible para el programador que lo haga?

    – Plátano

    4 de enero de 2019 a las 11:54

  • De hecho, este es un detalle de implementación para la api malloc y no hay una api para recuperar esta información de manera estándar (que yo sepa). El “sistema” lo registra y lo usa en free. Tal vez la respuesta no lo satisfaga, pero no creo que obtenga una con información más genéricamente aplicable 🙂

    – jdehaan

    20 de enero de 2019 a las 18:32

avatar de usuario
DigitalRoss

La técnica original consistía en asignar un bloque un poco más grande y almacenar el tamaño al principio, y luego darle a la aplicación el resto del blog. El espacio adicional contiene un tamaño y posiblemente enlaces para unir los bloques libres para su reutilización.

Sin embargo, hay ciertos problemas con esos trucos, como el comportamiento deficiente de la memoria caché y la gestión de la memoria. Usar la memoria directamente en el bloque tiende a paginar las cosas innecesariamente y también crea páginas sucias que complican el uso compartido y la copia en escritura.

Entonces, una técnica más avanzada es mantener un directorio separado. También se han desarrollado enfoques exóticos en los que las áreas de la memoria utilizan los mismos tamaños de potencia de dos.

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

  • Esta es una no respuesta. La pregunta es exactamente esta: ¿por qué Free puede buscar de manera confiable el tamaño del bloque, pero aún así no hay ninguna función disponible para el programador que lo haga?

    – Plátano

    4 de enero de 2019 a las 11:54

  • De hecho, este es un detalle de implementación para la api malloc y no hay una api para recuperar esta información de manera estándar (que yo sepa). El “sistema” lo registra y lo usa en free. Tal vez la respuesta no lo satisfaga, pero no creo que obtenga una con información más genéricamente aplicable 🙂

    – jdehaan

    20 de enero de 2019 a las 18:32

avatar de usuario
E Fraim

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

¿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