Почему размер структуры должен быть кратным наибольшему выравниванию любого члена структуры
Я понимаю заполнение, которое происходит между членами структуры для обеспечения правильного выравнивания отдельных типов. Однако, почему структура данных должна быть кратна выравниванию наибольшего члена? Я не понимаю, что заполнение необходимо в конце.
Ссылка: http://en.wikipedia.org/wiki/Data_structure_alignment
4 ответа
Хороший вопрос. Рассмотрим этот гипотетический тип:
struct A {
int n;
bool flag;
};
Итак, объект типа A
должно занимать пять байтов (четыре для int плюс один для bool), но на самом деле это занимает восемь. Зачем?
Ответ виден, если вы используете такой тип:
const size_t N = 100;
A a[N];
Если каждый A
были только пять байтов, то a[0]
будет выравнивать, но a[1]
, a[2]
и большинство других элементов не будет.
Но почему выравнивание имеет значение? Есть несколько причин, связанных с аппаратным обеспечением. Одна из причин заключается в том, что недавно / часто используемая память кэшируется в строках кэша на кремнии ЦП для быстрого доступа. Выровненный объект, меньший, чем строка кэша, всегда помещается в одну строку (но см. Интересные комментарии, приложенные ниже), но невыровненный объект может занимать две строки, тратя кеш-память.
На самом деле существуют еще более фундаментальные аппаратные причины, связанные с тем, как данные с байтовой адресацией передаются по 32- или 64-битной шине данных, совершенно отдельно от строк кэша. Не только смещение приведет к засорению шины дополнительными выборками (как и раньше, из-за перераспределения), но также заставит регистры сдвигать байты по мере их поступления. Еще хуже то, что смещение приводит к путанице в логике оптимизации (по крайней мере, в руководстве по оптимизации Intel говорится, что это так, хотя у меня нет личных знаний об этом последнем пункте). Таким образом, смещение очень плохо с точки зрения производительности.
По этим причинам обычно стоит тратить байты заполнения.
Обновление: комментарии ниже все полезны. Я рекомендую их.
В зависимости от аппаратного обеспечения выравнивание может быть необходимым или просто помочь ускорить выполнение.
Существует определенное количество процессоров (я полагаю, что ARM), в которых невыровненный доступ приводит к аппаратному исключению. Легко и просто.
Несмотря на то, что типичные процессоры x86 более снисходительны, за доступ к невыровненным фундаментальным типам все еще накладывается штраф, поскольку процессору приходится выполнять больше работы, чтобы вносить биты в регистр, прежде чем он сможет работать с ним. Компиляторы обычно предлагают определенные атрибуты / прагмы, когда упаковка все же желательна.
Если размер регистра ЦП составляет 32 бита, то он может захватить память, находящуюся на 32-битных границах, с помощью одной инструкции сборки. Он медленнее захватывает 32 бита, а затем получает байт, который начинается с бита 8.
Кстати: там не должно быть padding. Вы можете попросить, чтобы структуры были упакованы.
Из-за виртуальной адресации.
"... выравнивание страницы по границе размера страницы позволяет аппаратным средствам сопоставлять виртуальный адрес с физическим адресом путем замены старших бит в адресе, а не выполнения сложной арифметики".
Кстати, я нашел страницу в Википедии об этом довольно хорошо написано.