utiliza usar como c memory-management malloc alignment realloc

usar - malloc realloc free c



¿Gestión de memoria alineada? (7)

  1. Experimenta en tu sistema. En muchos sistemas (especialmente en los de 64 bits), obtiene la memoria alineada de 16 bytes de malloc() todos modos. De lo contrario, deberá asignar el espacio adicional y mover el puntero (como máximo 8 bytes en casi todas las máquinas).

    Por ejemplo, Linux de 64 bits en x86 / 64 tiene un long double 16 bytes, que está alineado a 16 bytes, por lo que todas las asignaciones de memoria están alineadas de 16 bytes de todos modos. Sin embargo, con un programa de 32 bits, sizeof(long double) es 8 y las asignaciones de memoria solo están alineadas con 8 bytes.

  2. Sí, solo puede free() el puntero devuelto por malloc() . Cualquier otra cosa es una receta para el desastre.

  3. Si su sistema realiza asignaciones alineadas de 16 bytes, no hay problema. Si no lo hace, entonces necesitará su propio reasignador, que realiza una asignación alineada de 16 bytes y luego copia los datos, o que utiliza el sistema realloc() y ajusta los datos realineados cuando sea necesario.

Comprueba la página de manual de tu malloc() ; Puede haber opciones y mecanismos para modificarlo para que se comporte como usted quiere.

En MacOS X, hay posix_memalign() y valloc() (que asigna una asignación alineada a la página), y hay toda una serie de funciones '' man malloc_zoned_malloc zonales'' identificadas por man malloc_zoned_malloc y el encabezado es <malloc/malloc.h> .

Tengo algunas preguntas relacionadas con la administración de bloques de memoria alineados. Las respuestas multiplataforma serían ideales. Sin embargo, como estoy bastante seguro de que no existe una solución multiplataforma, estoy principalmente interesado en Windows y Linux y, en gran medida, en Mac OS y FreeBSD.

  1. ¿Cuál es la mejor manera de alinear un trozo de memoria en los límites de 16 bytes? (Soy consciente del método trivial de usar malloc() , asignar un poco de espacio adicional y luego colocar el puntero en un valor alineado correctamente. Sin embargo, estoy esperando algo un poco menos de kludge-y, también. abajo para cuestiones adicionales)

  2. Si uso malloc() antiguo y llano, malloc() espacio adicional y luego muevo el puntero hasta donde se alinearía correctamente, ¿es necesario mantener el puntero al principio del bloque para liberarlo? (Llamar free() en los punteros a la mitad del bloque parece funcionar en la práctica en Windows, pero me pregunto qué dice la norma y, incluso si la norma dice que no puede, si funciona en la práctica en todas las principales OS. No me importa el DS9K oscuro DS9K como los OS).

  3. Esta es la parte difícil / interesante . ¿Cuál es la mejor manera de reasignar un bloque de memoria mientras se preserva la alineación? Idealmente, esto sería algo más inteligente que llamar a malloc() , copiar y luego llamar a free() en el bloque anterior. Me gustaría hacerlo en el lugar donde sea posible.


  1. No tengo conocimiento de ninguna forma de solicitar memoria de retorno malloc con una alineación más estricta de lo normal. En cuanto a "usual" en Linux, desde man posix_memalign (que puede usar en lugar de malloc () para obtener una memoria más estrictamente alineada si lo desea):

    GNU libc malloc () siempre devuelve direcciones de memoria alineadas de 8 bytes, por lo que estas rutinas solo son necesarias si necesita valores de alineación más grandes.

  2. Debe liberar () la memoria utilizando el mismo puntero devuelto por malloc (), posix_memalign () o realloc ().

  3. Use realloc () como de costumbre, incluyendo suficiente espacio adicional, de modo que si se devuelve una nueva dirección que aún no está alineada, puede eliminarla () ligeramente para alinearla. Desagradable, pero lo mejor que se me ocurre.


  1. Si su implementación tiene un tipo de datos estándar que necesita una alineación de 16 bytes (por ejemplo, long long ), malloc ya garantiza que los bloques devueltos se alinearán correctamente. La sección 7.20.3 de los estados de C99 The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object.

  2. Debe devolver la misma dirección exacta a free que le dio malloc . Sin excepciones. Así que sí, necesitas guardar la copia original.

  3. Vea (1) arriba si ya tiene un tipo requerido de alineación de 16 bytes.

Más allá de eso, es posible que la implementación de malloc le brinde direcciones alineadas de 16 bytes para la eficiencia, aunque no está garantizado por la norma. Si lo requiere, siempre puede implementar su propio asignador.

En mi caso, implementaría una capa malloc16 sobre malloc que usaría la siguiente estructura:

some padding for alignment (0-15 bytes) size of padding (1 byte) 16-byte-aligned area

Luego malloc16() su función malloc16() llame a malloc para obtener un bloque de 16 bytes más grande que el solicitado, determine dónde debe estar el área alineada, coloque la longitud del relleno justo antes de eso y devuelva la dirección del área alineada.

Para free16 , simplemente free16 el byte antes de la dirección dada para obtener la longitud de relleno, trabajarás la dirección real del bloque malloc''ed a partir de eso, y la pasarás a free .

Esto no se ha probado, pero debería ser un buen comienzo:

void *malloc16 (size_t s) { unsigned char *p; unsigned char *porig = malloc (s + 0x10); // allocate extra if (porig == NULL) return NULL; // catch out of memory p = (porig + 16) & (~0xf); // insert padding *(p-1) = p - porig; // store padding size return p; } void free16(void *p) { unsigned char *porig = p; // work out original porig = porig - *(porig-1); // by subtracting padding free (porig); // then free that }

La línea mágica en el malloc16 es p = (porig + 16) & (~0xf); lo que agrega 16 a la dirección, luego establece los 4 bits más bajos en 0, en efecto, regresando al siguiente punto de alineación más bajo (el +16 garantiza que está más allá del inicio real del bloque maloc''ed).

Ahora, no reclamo que el código anterior sea otra cosa que no sea kludgey. Tendrías que probarlo en las plataformas de interés para ver si es viable. Su principal ventaja es que extrae lo feo para que nunca tengas que preocuparte por eso.


Al iniciar un C11, tienes void *aligned_alloc( size_t alignment, size_t size ); Primitivas, donde los parámetros son:

alineación : especifica la alineación. Debe ser una alineación válida soportada por la implementación. tamaño - número de bytes para asignar. Un múltiplo integral de alineación.

Valor de retorno

En caso de éxito, devuelve el puntero al principio de la memoria recién asignada. El puntero devuelto debe ser desasignado con free () o realloc ().

En caso de fallo, devuelve un puntero nulo.

Ejemplo :

#include <stdio.h> #include <stdlib.h> int main(void) { int *p1 = malloc(10*sizeof *p1); printf("default-aligned addr: %p/n", (void*)p1); free(p1); int *p2 = aligned_alloc(1024, 1024*sizeof *p2); printf("1024-byte aligned addr: %p/n", (void*)p2); free(p2); }

Salida posible:

default-aligned addr: 0x1e40c20 1024-byte aligned addr: 0x1e41000


El requerimiento más difícil es obviamente el tercero, ya que cualquier solución basada en malloc() / realloc() es rehén de realloc() moviendo el bloque a una alineación diferente.

En Linux, puede usar asignaciones anónimas creadas con mmap() lugar de malloc() . Las direcciones devueltas por mmap() están necesariamente alineadas con la página, y la asignación puede extenderse con mremap() .


Es posible que pueda jimmy (en Microsoft VC ++ y quizás otros compiladores):

#pragma pack(16)

de manera que malloc () se ve obligado a devolver un puntero alineado de 16 bytes. Algo a lo largo de las líneas de:

ptr_16byte = malloc( 10 * sizeof( my_16byte_aligned_struct ));

Si funcionara para malloc (), creo que también funcionaría para realloc ().

Solo un pensamiento.

pete


Podría escribir su propio asignador de planchones para manejar sus objetos, podría asignar páginas a la vez usando mmap , mantener un caché de direcciones recientemente liberadas para asignaciones rápidas, manejar toda su alineación por usted y darle la flexibilidad para moverse / crecer Objetos exactamente como usted necesita. malloc es bastante bueno para asignaciones de propósito general, pero si conoce sus necesidades de distribución y distribución de datos, puede diseñar un sistema que cumpla exactamente con esos requisitos.