Я также хочу знать, делает ли это glibc malloc ().
Что такое выровненное распределение памяти?
Ответы (4)
Требования выравнивания определяют, какие смещения адресов могут быть назначены каким типам. Это полностью зависит от реализации, но обычно зависит от размера слова. Например, некоторые 32-битные архитектуры требуют, чтобы все int
переменные начинались с числа, кратного четырем. На некоторых архитектурах требования к выравниванию являются абсолютными. В других случаях (например, x86) их игнорирование приводит только к снижению производительности.
malloc
требуется для возврата адреса, подходящего для любых требований по выравниванию. Другими словами, возвращаемый адрес может быть назначен указателю любого типа. Из C99 §7.20.3 (функции управления памятью):
Указатель, возвращаемый в случае успешного выделения, выравнивается соответствующим образом, чтобы его можно было назначить указателю на любой тип объекта, а затем использовать для доступа к такому объекту или массиву таких объектов в выделенном пространстве (до тех пор, пока пространство не будет явно освобождено) .
Предположим, у вас есть структура.
struct S {
short a;
int b;
char c, d;
};
Без выравнивания он был бы размещен в памяти следующим образом (при условии 32-битной архитектуры):
0 1 2 3 4 5 6 7
|a|a|b|b|b|b|c|d| bytes
| | | words
Проблема в том, что на некоторых архитектурах ЦП инструкция по загрузке 4-байтового целого числа из памяти работает только на границах слов. Таким образом, ваша программа должна будет получать каждую половину b
с отдельными инструкциями.
Но если бы память была выложена как:
0 1 2 3 4 5 6 7 8 9 A B
|a|a| | |b|b|b|b|c|d| | |
| | | |
Тогда доступ к b
становится простым. (Недостатком является то, что требуется больше памяти из-за байтов заполнения.)
У разных типов данных разные требования к выравниванию. Обычно char
выравнивается по 1 байту, short
- по 2 байта, а 4-байтовые типы (int
, float
и указатели в 32-разрядных системах) выравниваются по 4 байтам.
Стандарт C требует, чтобы malloc
возвращал указатель, который правильно выровнен для любого типа данных.
glibc malloc
на x86-64 возвращает указатели с выравниванием по 16 байт.
Если у вас есть особые потребности в выравнивании памяти (для определенного оборудования или библиотек), вы можете воспользоваться непереносимыми распределителями памяти, такими как _ 1_ и _ 2_. Их можно легко абстрагировать за «переносным» интерфейсом, но, к сожалению, они нестандартны.
В документации malloc()
говорится:
[...] the allocated memory that is suitably aligned for any kind of variable.
Что верно почти для всего, что вы делаете на C / C ++. Однако, как указывали другие, существует множество особых случаев, требующих особого согласования. Например, процессоры Intel поддерживают 256-битный тип: __m256
, который, безусловно, не принимается во внимание malloc()
.
Точно так же, если вы хотите выделить буфер памяти для данных, которые должны быть выгружены (аналогично адресам, возвращаемым mmap()
и т. Д.), Вам понадобится, возможно, очень большое выравнивание, которое будет тратить много памяти, если malloc()
должен всегда возвращать буферы выровнен с такими границами.
В Linux или других системах Unix я предлагаю вам использовать функцию posix_memalign()
:
int posix_memalign(void **memptr, size_t alignment, size_t size);
Это самая актуальная функция, которую можно использовать для таких нужд.