Я работаю над менеджером памяти с помощью книги Архитектура игрового движка.
Сейчас я читаю о выравнивании памяти (в книге и в Интернете) и не уверен, как правильно использовать выравнивание для классов. Я понимаю концепцию выравнивания памяти (например, 4-байтовый блок данных должен быть расположен по адресу, оканчивающемуся на 0x0, 0x4, 0x8 или 0xC), но на allocateAligned()
-функция в книге — это комментарий, который говорит, что выравнивание должно быть степенью двойки. Если у меня есть класс, который имеет два int
И один char
, sizeof(classs)
говорит мне, что класс имеет размер 12 байт. Итак, вы бы передали 32 как выравнивание? Не будет ли это пустой тратой памяти и может привести к фрагментации?
Мой вопрос: как правильно выровнять классы, не могли бы вы объяснить мне это более подробно (что произойдет, если вы хотите выровнять большие фрагменты данных, например, 121 байт), и имеет ли смысл выравнивать более крупные фрагменты (потому что процессор извлекает только 8 байтов за один вызов, если я правильно информирован)?
Выравнивание типа никогда не может быть больше, чем размер типа. Это потому, что в массиве не может быть заполнения между элементами.
Не менее важно то, что выравнивание типа может быть меньше чем размер типа.
Давайте рассмотрим тип вашего класса: у него три члена, два 4-байтовых целых и одно 2-байтовое целое. Давайте предположим, что выравнивание 4-байтового целого числа составляет 4 байта, а выравнивание 2-байтового целого числа составляет 2 байта (это распространено). В этом случае выравнивание вашего типа класса составляет всего 4 байта. Он может быть расположен на любой 4-байтовой границе, и каждый из его членов будет правильно выровнен.
Вот почему ваш тип класса имеет два байта заполнения: 12 делится на четыре равномерно, а 10 — нет. Если бы у вашего класса не было заполнения, его размер был бы всего 10 байтов, а в массиве элементов половина объектов была бы выровнена.
Выравнивание типа может быть меньше, но не больше его размера. В типичной 32-битной реализации ваш
struct X {
int a;
int b;
char c;
};
скорее всего sizeof(X) == 12
а также alignof(X) == 4
, Очевидно, вы не можете иметь X
каждые четыре байта, потому что они будут перекрываться, но выравнивание означает, что 0x1000
, 0x1004
, 0x1008
, а также 0x100c
все потенциальные места вы может быть начать X
,
Обратите внимание, что размер шрифта возвращается sizeof
всегда кратно выравниванию, так как sizeof
определяет количество байтов между элементами массива, и вы не хотите, чтобы первая запись в массиве была выровнена, а не вторая.