Что такое выровненное распределение памяти?

Я также хочу знать, делает ли это glibc malloc ().


person Anonymous    schedule 22.10.2010    source источник
comment
не будет ли это зависеть от целевой архитектуры? Это почти наверняка выровнено ...   -  person Mitch Wheat    schedule 22.10.2010


Ответы (4)


Требования выравнивания определяют, какие смещения адресов могут быть назначены каким типам. Это полностью зависит от реализации, но обычно зависит от размера слова. Например, некоторые 32-битные архитектуры требуют, чтобы все int переменные начинались с числа, кратного четырем. На некоторых архитектурах требования к выравниванию являются абсолютными. В других случаях (например, x86) их игнорирование приводит только к снижению производительности.

malloc требуется для возврата адреса, подходящего для любых требований по выравниванию. Другими словами, возвращаемый адрес может быть назначен указателю любого типа. Из C99 §7.20.3 (функции управления памятью):

Указатель, возвращаемый в случае успешного выделения, выравнивается соответствующим образом, чтобы его можно было назначить указателю на любой тип объекта, а затем использовать для доступа к такому объекту или массиву таких объектов в выделенном пространстве (до тех пор, пока пространство не будет явно освобождено) .

person Matthew Flaschen    schedule 22.10.2010
comment
ссылка, которую вы предоставляете, не подходит. не могли бы вы предоставить еще один? У этого есть несколько проблем! Ty - person Cătălina Sîrbu; 02.09.2020

Предположим, у вас есть структура.

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 байт.

person dan04    schedule 22.10.2010
comment
извините, я не понимаю, что вы имеете в виду, когда char обычно выровнен по 1 байту, сокращен до 2 байтов и 4 байта. - person Anni_housie; 19.11.2016
comment
@Anni_housie это просто означает, что большинство систем обычно используют 1 байт памяти для хранения char, 2 байта для хранения коротких, 4 байта для int / float / pointer и т. Д. - person Paa K; 19.11.2016
comment
Или вы можете просто переупорядочить элементы в своей структуре, чтобы сначала было int, затем короткое, а затем два символа ... таким образом, система будет легко их читать. - person Omarito; 05.05.2019

Если у вас есть особые потребности в выравнивании памяти (для определенного оборудования или библиотек), вы можете воспользоваться непереносимыми распределителями памяти, такими как _ 1_ и _ 2_. Их можно легко абстрагировать за «переносным» интерфейсом, но, к сожалению, они нестандартны.

person André Caron    schedule 22.10.2010

В документации 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);

Это самая актуальная функция, которую можно использовать для таких нужд.

person Alexis Wilke    schedule 26.12.2012