Вопрос о выравнивании указателя
Вопрос
Я работаю над реализацией пула памяти, и меня немного смущает выравнивание указателей...
Предположим, что у меня есть пул памяти, который выдает блоки памяти фиксированного размера, в момент создания пула памяти я malloc((размер)*(количество блоков)).Если то, что выделяется, является объектами, а размер определяется оператором sizeof, выравнивание не должно вызывать беспокойства, но если размер неравномерен (по какой-либо причине ему нужны блоки по 100 байт), то, когда я разделяю фрагмент, предоставленный malloc, я получаю невыровненные указатели.Мой вопрос в том, должен ли я всегда выравнивать блоки по некоторой границе, и если да, то по какой?
Решение
X86 будет работать без выравнивания, но при выравнивании данных производительность выше. Выравнивание для type обычно имеет размер sizeof ( type ), максимум до 16 (байтов).
Я написал эту глупую тестовую программу просто для уверенности (предполагая, что malloc знает, что делает), и она возвращает 16 на моей коробке amd64. Возвращает 8 при компиляции в 32-битном режиме:
#include <stdlib.h>
#include <stdio.h>
int main() {
int i;
unsigned long used_bits = 0, alignment;
for (i = 0; i < 1000; ++i) {
used_bits |= (unsigned long)malloc(1); /* common sizes */
used_bits |= (unsigned long)malloc(2);
used_bits |= (unsigned long)malloc(4);
used_bits |= (unsigned long)malloc(8);
used_bits |= (unsigned long)malloc(16);
used_bits |= (unsigned long)malloc(437); /* random number */
}
alignment = 1;
while (!(used_bits & alignment)) {
alignment <<= 1;
}
printf("Alignment is: %lu\n", alignment);
return 0;
}
Другие советы
Правильное выравнивание, по крайней мере, полезно (с точки зрения производительности) в большинстве реализаций x86 (и какое-то выравнивание фактически обязательно в других архитектурах).Вы могли бы запросить (как это делает calloc) пару аргументов, размер элементов в байтах и количество элементов, а не только один (размер в байтах, как это делает malloc);затем вы можете внутренне выровнять (путем округления размеров блоков) до следующей степени, превышающей размер элемента на 2 (но переключитесь на значения, кратные 16 байтам выше 16, не продолжайте удваивать вечно, как рекомендует и объясняет @derobert!-).Таким образом, если вызывающей стороне просто нужно N байт без какого-либо выравнивания или заполнения, они всегда могут запросить N элементов по 1 байту каждый (точно так же, как с calloc и по той же причине;-).