Ограничения выравнивания для malloc () / free () - PullRequest
8 голосов
/ 31 августа 2008

Старые K & R (2-е изд.) И другие тексты на языке C, которые я читал, в которых обсуждается реализация динамического распределителя памяти в стиле malloc() и free(), обычно также мимоходом упоминается что-то о типе данных ограничения выравнивания. Очевидно, что определенные аппаратные архитектуры компьютера (ЦП, регистры и доступ к памяти) ограничивают способы хранения и адресации определенных типов значений. Например, может существовать требование, чтобы 4-байтовое (long) целое число было сохранено, начиная с адресов, кратных четырем.

Какие ограничения, если таковые имеются, накладывают основные платформы (Intel & AMD, SPARC, Alpha) для выделения памяти и доступа к памяти, или я могу безопасно игнорировать выравнивание распределения памяти по конкретным границам адресов?

Ответы [ 5 ]

6 голосов
/ 06 сентября 2008

Sparc, MIPS, Alpha и большинство других «классических RISC» архитектур допускают только выровненный доступ к памяти даже сегодня. Нераспределенный доступ вызовет исключение, но некоторые операционные системы будут обрабатывать это исключение путем копирования с нужного адреса в программном обеспечении с использованием меньших загрузок и хранилищ. Код приложения не будет знать, что возникла проблема, за исключением того, что производительность будет очень плохой.

MIPS имеет специальные инструкции (lwl и lwr), которые можно использовать для доступа к 32-битным величинам с невыровненных адресов. Всякий раз, когда компилятор может сказать, что адрес, скорее всего, не выровнен, он будет использовать эту последовательность двух команд вместо обычной инструкции lw.

x86 может обрабатывать доступ к памяти без выравнивания на аппаратном уровне без исключения, но при этом все еще наблюдается снижение производительности в 3 раза по сравнению с выравниванием доступа.

Ульрих Дреппер написал исчерпывающую статью по этой и другим темам, связанным с памятью, Что каждый программист должен знать о памяти . Это очень длинная рецензия, но наполненная жевательной добротой.

4 голосов
/ 31 августа 2008

Выравнивание по-прежнему очень важно сегодня. Некоторые процессоры (на ум приходит семейство 68k) выдают исключение, если вы пытаетесь получить доступ к значению слова на нечетной границе. Сегодня большинство процессоров запускают два цикла памяти для извлечения невыровненного слова, но это определенно будет медленнее, чем выровненное извлечение. Некоторые другие процессоры даже не выдают исключение, но будут извлекать неверное значение из памяти!

Если по какой-либо иной причине, кроме производительности, разумно попытаться следовать настройкам выравнивания вашего процессора. Обычно ваш компилятор позаботится обо всех деталях, но если вы делаете что-то, где вы сами размечаете структуру памяти, тогда стоит подумать.

1 голос
/ 06 сентября 2008

Обратите внимание, что даже на IA-32 и AMD64 для некоторых инструкций / встроенных функций SSE требуются согласованные данные. Эти инструкции выдают исключение, если данные не выровнены, так что, по крайней мере, вам не придется отлаживать ошибки «неправильных данных». Также есть эквивалентные невыровненные инструкции, но, как говорит Дентон, они медленнее.

Если вы используете VC ++, кроме директив #pragma pack у вас также есть директивы __declspec (align) для точного выравнивания. В документации VC ++ также упоминается функция __aligned_malloc для особых требований выравнивания.

Как правило, если вы не перемещаете данные по компиляторам / языкам или не используете инструкции SSE, вы, вероятно, можете игнорировать проблемы выравнивания.

1 голос
/ 31 августа 2008

Как упомянул Грег, это все еще важно сегодня (возможно, в некоторой степени), и компиляторы обычно заботятся о выравнивании, основываясь на цели архитектуры. В управляемых средах JIT-компилятор может оптимизировать выравнивание на основе архитектуры времени выполнения.

Вы можете увидеть прагматические директивы (в C / C ++), которые изменяют выравнивание. Это следует использовать только тогда, когда требуется очень специфическое выравнивание.

// For example, this changes the pack to 2 byte alignment.
#pragma pack(2)
1 голос
/ 31 августа 2008

Вам все равно нужно знать о проблемах выравнивания при разметке класса или структуры в C (++). В этих случаях компилятор сделает все правильно, но общий размер структуры / класса может оказаться более бесполезным, чем необходимо

Например:

struct
{ 
    char A;
    int B;
    char C;
    int D;
};

будет иметь размер 4 * 4 = 16 байт (предположим, Windows на x86), тогда как

struct
{ 
    char A;
    char C;
    int B;
    int D;
};

будет иметь размер 4 * 3 = 12 байт.

Это связано с тем, что компилятор применяет 4-байтовое выравнивание для целых чисел, но только 1 байт для символов.

Как правило, пакетные переменные-члены одного размера (типа) объединяются, чтобы минимизировать потерянное пространство.

...