Основы ЭВМ
Теория: Блоки, байты и выравнивание
В первых компьютерах всё было просто. Процессор читал данные по одному байту, и этого хватало. Программ было мало, память маленькая, и никто не задумывался о правилах хранения. Но со временем задачи стали сложнее. Читать по одному байту оказалось слишком медленно. Пришлось брать данные кусками — блоками. Это ускорило работу, но принесло новые трудности.
Сначала процессор начал спотыкаться, когда данные лежали «криво», не по границе блока. Потом выяснилось, что разные процессоры по-разному раскладывают байты внутри числа. А позже к этому добавилось новое ограничение — границы страниц памяти. Каждое из этих затруднений требовало своего решения.
Компьютер не работает с памятью по одному биту. Он всегда берёт данные блоками. Минимальный кусок — байт, но процессор может читать больше: слова, двойные слова и даже целые кэш-линии (чаще всего по 64 байта). Размер блока определяет, сколько информации переносится за одну операцию.
Представим процессор, который читает по 4 байта за раз. В памяти лежит число AB CD EF 01. Оно начинается с адреса, кратного четырём — процессор делает одно чтение и получает всё число сразу.
Теперь другое число — 23 45 67 89, но оно начинается с адреса 2. В первом блоке процессор видит .. 23 45 67, а во втором — 89 .. .. ... Чтобы собрать число целиком, ему приходится читать два блока, и работа замедляется.
Поэтому появилось правило выравнивания: если число занимает 4 байта, оно должно начинаться с адреса, делящегося на 4. Тогда процессор получает его за одно чтение.
В современных системах принцип тот же, только масштаб больше. Процессор читает память кэш-линиями по 64 байта. Даже если программе нужно всего несколько байт, он загружает всю линию в кэш. Это ускоряет работу и использует принцип пространственной локальности — если нужен один элемент, с большой вероятностью скоро понадобятся и соседние.
Размер блока напрямую влияет на скорость. Большие блоки позволяют переносить больше данных за раз, но иногда программа запрашивает совсем маленький кусок и занимает лишнее. Если блоки слишком маленькие, система тратит время на их объединение. Баланс между этими крайностями задаёт сама архитектура компьютера.
Возьмём число 0x12345678. В памяти оно может храниться по-разному:
- Little-endian:
78 56 34 12 - Big-endian:
12 34 56 78
Для человека это одно и то же число. Но процессор читает байты по-своему. Если данные записаны в little-endian, а процессор ожидает big-endian, то вместо 0x12345678 он получит 0x78563412.
Такое расхождение особенно заметно в сетях и протоколах: если стороны не договорились о порядке байтов, данные окажутся искажёнными.
Современные операционные системы делят память на страницы фиксированного размера, например по 4 КБ. Это удобно для управления и защиты, но создаёт новую проблему.
Представим структуру размером 512 байт. Если она начинается в начале страницы, то целиком помещается внутрь неё. Но если структура начинается за 100 байт до конца страницы, то оставшиеся 412 байт перепрыгивают на следующую страницу. Теперь процессору приходится обращаться к двум страницам вместо одной. Это значит лишние операции и больше времени.
Если не учитывать эти правила, появляются странные ошибки и падения. Выравнивание может превратить простую операцию в двойное чтение. Разный порядок байтов — в искажение чисел. А пересечение границы страниц — в неожиданные тормоза программы. Эти ошибки сложно заметить, но они напрямую влияют на производительность.

