По общему признанию, я этого не понимаю. Скажем, у вас есть память со словом памяти длиной 1 байт. Почему вы не можете получить доступ к переменной длиной 4 байта при одном доступе к памяти по невыровненному адресу (т.е. не делящемуся на 4), как в случае с выровненными адресами?
Цель выравнивания памяти
Ответы (8)
Это ограничение многих базовых процессоров. Обычно это можно обойти, выполнив 4 неэффективных выборки одного байта, а не одну эффективную выборку слова, но многие спецификаторы языка решили, что будет проще просто объявить их вне закона и принудительно выровнять все.
В этой ссылке содержится гораздо больше информации, обнаруженной OP.
Подсистема памяти на современном процессоре ограничена доступом к памяти на уровне детализации и выравнивании ее размера слова; это так по ряду причин.
Скорость
Современные процессоры имеют несколько уровней кэш-памяти, через которые должны протягиваться данные; поддержка однобайтовых чтений привела бы к тому, что пропускная способность подсистемы памяти была бы жестко привязана к пропускной способности исполнительного модуля (также известной как cpu-bound); все это напоминает о том, как режим PIO превзошел DMA по многим из тех же причин в жестких дисках.
ЦП всегда читает с размером слова (4 байта на 32-разрядном процессоре), поэтому, когда вы выполняете доступ по невыровненному адресу - на процессоре, который его поддерживает, процессор будет читать несколько слов. . ЦП будет читать каждое слово памяти, которое охватывает ваш запрошенный адрес. Это приводит к двукратному увеличению количества транзакций памяти, необходимых для доступа к запрошенным данным.
Из-за этого очень легко может быть медленнее читать два байта, чем четыре. Например, предположим, что у вас есть структура в памяти, которая выглядит так:
struct mystruct {
char c; // one byte
int i; // four bytes
short s; // two bytes
}
На 32-битном процессоре он, скорее всего, будет выровнен, как показано здесь:

Процессор может читать каждого из этих элементов за одну транзакцию.
Допустим, у вас есть упакованная версия структуры, возможно, из сети, куда она была упакована для эффективности передачи; это может выглядеть примерно так:

Чтение первого байта будет таким же.
Когда вы просите процессор дать вам 16 бит из 0x0005, он должен будет прочитать слово из 0x0004 и сдвинуть влево на 1 байт, чтобы поместить его в 16-битный регистр; некоторая дополнительная работа, но большинство может справиться с ней за один цикл.
Когда вы запрашиваете 32 бита от 0x0001, вы получаете 2-кратное усиление. Процессор считывает из 0x0000 в регистр результатов и сдвигает влево на 1 байт, затем снова считывает из 0x0004 во временный регистр, сдвигает вправо на 3 байта, затем OR вместе с регистром результатов.
Диапазон
Для любого заданного адресного пространства, если архитектура может предполагать, что 2 младших бита всегда равны 0 (например, 32-битные машины), тогда она может получить доступ в 4 раза больше памяти (2 сохраненных бита могут представлять 4 различных состояния) или такое же количество памяти с 2 битами для чего-то вроде флагов. Удаление 2 младших битов из адреса даст вам 4-байтовое выравнивание; также называется шагом размером 4 байта. Каждый раз, когда адрес увеличивается, он фактически увеличивает бит 2, а не бит 0, т.е. последние 2 бита всегда будут равны 00.
Это может даже повлиять на физический дизайн системы. Если для адресной шины требуется на 2 бита меньше, на ЦП может быть на 2 контакта меньше, а на печатной плате - на 2 меньше.
Атомарность
ЦП может работать с выровненным словом памяти атомарно, что означает, что никакая другая инструкция не может прервать эту операцию. Это критически важно для правильной работы многих структуры данных без блокировок и другие парадигмы параллелизма.
Заключение
Система памяти процессора несколько сложнее и сложнее, чем описано здесь; может помочь обсуждение того, как на самом деле процессор x86 обращается к памяти (многие процессоры работают аналогично ).
Соблюдение выравнивания памяти дает еще много преимуществ, о которых вы можете прочитать в этой статье IBM.
Основное назначение компьютера - преобразование данных. Современные архитектуры и технологии памяти оптимизировались на протяжении десятилетий, чтобы упростить получение большего количества данных, входящих и исходящих, а также между большим количеством и более быстрыми исполнительными модулями - высоконадежным способом.
Бонус: Тайники
Другое выравнивание по производительности, о котором я упоминал ранее, - это выравнивание строк кэша, которые (например, на некоторых процессорах) имеют размер 64B.
Для получения дополнительной информации о том, какую производительность можно повысить за счет использования кешей, см. Галерея эффектов кэша процессора; из этого вопроса о размерах строк кэша
Понимание строк кэша может быть важным для некоторых типов оптимизации программ. Например, выравнивание данных может определять, касается ли операция одной или двух строк кэша. Как мы видели в приведенном выше примере, это может легко означать, что в случае смещения, операция будет в два раза медленнее.
mystruct неверно. Структуры C всегда выравниваются по выравниванию самого большого члена, поэтому после s должно быть два дополнительных байта заполнения.
- person Martin; 16.12.2015
The CPU can operate on an aligned word of memory atomically, как понять это предложение? IMO, операция с памятью не всегда будет атомарной, как ++i, процедура может быть следующей: 1. чтение значения i в регистр 2. регистр приращения 3. сохранение значения регистра в i
- person cifer; 04.04.2016
movq). Точно так же многие 32-битные ARM гарантируют атомарность пары нагрузки.
- person Peter Cordes; 19.08.2020
вы можете с некоторыми процессорами (Nehalem может это сделать), но раньше весь доступ к памяти был выровнен по 64-битной (или 32-битной) строке, поскольку шина имеет ширину 64 бита, вам приходилось получать 64-битные данные за раз, и было значительно проще получить эти выровненными «кусками» по 64 бита.
Итак, если вы хотели получить один байт, вы выбирали 64-битный фрагмент, а затем замаскировали ненужные биты. Легко и быстро, если ваш байт находится на правом конце, но если он находится в середине этого 64-битного фрагмента, вам придется замаскировать нежелательные биты, а затем переместить данные в нужное место. Хуже того, если вам нужна 2-байтовая переменная, но она была разделена на 2 части, тогда для этого требовалось удвоение требуемого доступа к памяти.
Итак, поскольку все думают, что память дешевая, они просто заставили компилятор выровнять данные по размерам блоков процессора, чтобы ваш код работал быстрее и эффективнее за счет потраченной впустую памяти.
По сути, причина в том, что шина памяти имеет определенную длину, которая намного, намного меньше, чем размер памяти.
Таким образом, ЦП считывает данные из встроенного кеша L1, который в наши дни часто составляет 32 КБ. Но шина памяти, соединяющая кэш L1 с процессором, будет иметь значительно меньшую ширину, чем размер строки кэша. Это будет порядка 128 бит.
So:
262,144 bits - size of memory
128 bits - size of bus
Неверно выровненные обращения иногда перекрывают две строки кэша, и это потребует полностью нового чтения кэша для получения данных. Он может даже пропустить весь путь к DRAM.
Более того, некоторая часть ЦП должна будет стоять на голове, чтобы собрать единый объект из этих двух разных строк кэша, каждая из которых содержит фрагмент данных. В одной строке это будут биты очень высокого порядка, а в другой - биты очень низкого порядка.
Будет выделенное оборудование, полностью интегрированное в конвейер, которое обрабатывает перемещение выровненных объектов на необходимые биты шины данных ЦП, но такого оборудования может не хватать для смещенных объектов, потому что, вероятно, имеет смысл использовать эти транзисторы для ускорения правильно оптимизированного программы.
В любом случае, второе чтение памяти, которое иногда необходимо, замедлит конвейер, независимо от того, сколько специального оборудования было (гипотетически и по глупости) выделено для исправления невыровненных операций с памятью.
@joshperry дал отличный ответ на этот вопрос. В дополнение к его ответу у меня есть несколько цифр, которые графически показывают описанные эффекты, особенно 2-кратное усиление. Вот ссылка на влияние различных таблиц Google, показывающее влияние различных выравнивания слов выглядят так. Кроме того, здесь есть ссылка на Github gist с кодом для теста. Тестовый код адаптирован из статьи Джонатана Ренцша, на которую ссылается @joshperry . Тесты проводились на Macbook Pro с четырехъядерным 64-разрядным процессором Intel Core i7 с тактовой частотой 2,8 ГГц и 16 ГБ оперативной памяти.
x и y?
- person shuva; 02.10.2018
Если система с памятью с байтовой адресацией имеет 32-разрядную шину памяти, это означает, что фактически существует четыре системы памяти с байтовой адресацией, которые все подключены для чтения или записи одного и того же адреса. Выровненное 32-битное чтение потребует информации, хранящейся по одному и тому же адресу во всех четырех системах памяти, поэтому все системы могут предоставлять данные одновременно. Невыровненное 32-битное чтение потребует, чтобы некоторые системы памяти возвращали данные с одного адреса, а некоторые - со следующего более высокого адреса. Хотя есть некоторые системы памяти, которые оптимизированы для выполнения таких запросов (в дополнение к их адресу, они фактически имеют сигнал «плюс один», который заставляет их использовать адрес, на единицу превышающий указанный), такая функция добавляет значительную стоимость. и сложность системы памяти; большинство обычных систем памяти просто не могут одновременно возвращать части разных 32-битных слов.
Если у вас 32-битная шина данных, адресные строки адресной шины, подключенные к памяти, будут начинаться с A 2, поэтому только 32-битные выровненные адреса могут быть доступны за один цикл шины.
Таким образом, если слово охватывает границу выравнивания адреса - то есть A 0 для 16/32-битных данных или A 1 для 32-битных данных не равны нулю, требуется два цикла шины для получить данные.
Некоторые архитектуры / наборы инструкций не поддерживают невыровненный доступ и будут генерировать исключение при таких попытках, поэтому сгенерированный компилятором невыровненный код доступа требует не только дополнительных циклов шины, но и дополнительных инструкций, что делает его еще менее эффективным.
На PowerPC вы можете без проблем загрузить целое число с нечетного адреса.
Sparc, I86 и (я думаю) Itatnium вызывают аппаратные исключения, когда вы пытаетесь это сделать.
Одна 32-битная загрузка против четырех 8-битных загрузок не будет иметь большого значения на большинстве современных процессоров. То, находятся ли данные в кеше или нет, будет иметь гораздо больший эффект.
