¿Qué hace posix_memalign/memalign?
memory memory-pool (6)
Además de la respuesta de Oli, quisiera señalar un tema aún más importante.
En las arquitecturas x86 recientes, una línea de caché, que es la cantidad más pequeña de datos que se puede recuperar de la memoria a la caché, es de 64 bytes. Supongamos que el tamaño de su estructura es de 56 bytes, tiene una gran variedad de ellos. Cuando busca un elemento, la CPU deberá emitir 2 solicitudes de memoria (podría emitir 2 solicitudes, incluso si está en el medio de la línea de caché). Eso es malo para el rendimiento, ya que tienes que esperar a la memoria, y usas más memoria caché, lo que finalmente da una mayor proporción de falta de memoria caché. En este caso, no es suficiente usar posix_memalign, pero debe rellenar o compactar su estructura para que esté en límites de 64 bytes.
Tener estructura de 40 bytes es mala suerte :)
Estoy tratando de entender qué funciones hacen memalign()
y posix_memalign()
. Leer la documentación disponible no ayudó.
¿Alguien puede ayudarme a entender cómo funciona y para qué se utiliza? O, tal vez, proporcione un ejemplo de uso?
Intento entender cómo funciona la memoria de Linux, necesito escribir mi propio grupo de memoria simple (montón de baja fragmentación).
Cómo funciona depende de la implementación. El propósito de la función es darle un bloque de memoria alineado de n bytes (la dirección de inicio del bloque es una multiplicación de n).
Como memalign está obsoleto (ref: página de manual), solo la diferencia entre malloc () y posix_memalign () se describirá aquí. malloc () está alineado en 8 bytes (por ejemplo, para RHEL de 32 bits), pero para posix_memalign (), la alineación es definible por el usuario. Para saber el uso de esto, quizás un buen ejemplo es establecer el atributo de memoria usando mprotect (). Para usar mprotect (), el puntero de memoria debe estar alineado con PAGE. Y así, si llama a posix_memalign () con pagesize como la alineación, entonces el puntero devuelto puede enviarse fácilmente a mprotect () para establecer los atributos de lectura-escritura-ejecutable. (por ejemplo, después de copiar los datos en el puntero de la memoria, puede configurarlo como atributo de solo lectura para evitar que se modifique). "El puntero devuelto de malloc ()" no se puede usar aquí.
Deffault malloc return puntero que son múltiplos de 8, es media malloc split memory to chunks tiene 8 bytes y comprueba la memoria libre al inicio de cada fragmento. Hay 2 caras de problema.
Un trozo más grande perderá más memoria, pero un trozo más grande ayudará a C a encontrar la memoria de trozos libres más rápido. memalign puede cambiar qué tan grande es ese pedazo. Si desea guardar la memoria, disminuya el tamaño del fragmento a 2 o 4. Si desea acelerar su aplicación, aumente el tamaño del fragmento a la potencia de 2.
Mientras que malloc
le da un trozo de memoria que podría tener cualquier alineación (el único requisito es que debe estar alineado para el tipo primitivo más grande compatible con la implementación), posix_memalign
le proporciona un trozo de memoria que garantiza que tiene la alineación solicitada.
Por lo tanto, el resultado de, por ejemplo, posix_memalign(&p, 32, 128)
será un fragmento de 128 bytes de memoria cuya dirección de inicio garantiza que será un múltiplo de 32.
Esto es útil para varias operaciones de bajo nivel (como el uso de instrucciones SSE o DMA) que requieren memoria que obedece a una alineación particular.
malloc
siempre devuelve la memoria que está configurada en la alineación máxima requerida por cualquiera de los tipos primitivos. Esto permite que la memoria malloc
''d almacene cualquier tipo que pueda necesitar. Mi comprensión de la descripción de posix_memalign
es que devuelve una ubicación de memoria cuya dirección será un múltiplo de lo que especifique como la alineación.
No estoy seguro de cuán útil sería esto al escribir un grupo de memoria personalizado, pero he intentado proporcionar un ejemplo de cómo esto podría implementarse. La diferencia está en mi ejemplo, cualquier cosa asignada con malloc_aligned
tiene que ser liberada con free_aligned
; sin embargo, con posix_memalign
puedes usar free
.
#include <stdlib.h>
#include <stdio.h>
void *malloc_aligned(size_t alignment, size_t bytes)
{
// we need to allocate enough storage for the requested bytes, some
// book-keeping (to store the location returned by malloc) and some extra
// padding to allow us to find an aligned byte. im not entirely sure if
// 2 * alignment is enough here, its just a guess.
const size_t total_size = bytes + (2 * alignment) + sizeof(size_t);
// use malloc to allocate the memory.
char *data = malloc(sizeof(char) * total_size);
if (data)
{
// store the original start of the malloc''d data.
const void * const data_start = data;
// dedicate enough space to the book-keeping.
data += sizeof(size_t);
// find a memory location with correct alignment. the alignment minus
// the remainder of this mod operation is how many bytes forward we need
// to move to find an aligned byte.
const size_t offset = alignment - (((size_t)data) % alignment);
// set data to the aligned memory.
data += offset;
// write the book-keeping.
size_t *book_keeping = (size_t*)(data - sizeof(size_t));
*book_keeping = (size_t)data_start;
}
return data;
}
void free_aligned(void *raw_data)
{
if (raw_data)
{
char *data = raw_data;
// we have to assume this memory was allocated with malloc_aligned.
// this means the sizeof(size_t) bytes before data are the book-keeping
// which points to the location we need to pass to free.
data -= sizeof(size_t);
// set data to the location stored in book-keeping.
data = (char*)(*((size_t*)data));
// free the memory.
free(data);
}
}
int main()
{
char *ptr = malloc_aligned(7, 100);
printf("is 5 byte aligned = %s/n", (((size_t)ptr) % 5) ? "no" : "yes");
printf("is 7 byte aligned = %s/n", (((size_t)ptr) % 7) ? "no" : "yes");
free_aligned(ptr);
return 0;
}