Почему Malloc() заботится о выравниваниях границ?
Я слышал, что malloc()
выравнивает память по типу, который выделяется. Например, из книги "Понимание и использование указателей C":
Выделенная память будет выровнена в соответствии с типом данных указателя. Например, четырехбайтовое целое будет выделено на границе адреса, равномерно делимой на четыре.
Если я последую, это означает, что
int *integer=malloc(sizeof(int));
будет распределяться по границе адреса, равномерно делимой на четыре. Даже без литья (int *)
на malloc.
Я работал на чат-сервере; Я читал о аналогичном эффекте с struct
s.
И я должен спросить: логично, почему имеет значение, на чем делится граница адреса? Что не так с распределением группы памяти на мелодию n*sizeof(int)
с использованием целого числа по адресу 129
?
Я знаю, как работает арифметика указателей *(integer+1)
, но я не могу понять важность границ...
Ответы
Ответ 1
Выделенная память будет выровнена в соответствии с данными указателя тип.
Если вы говорите о malloc
, это ложь. malloc
не заботится о том, что вы делаете с данными, и выделяет выделенную память в соответствии с самым строгим собственным типом реализации.
Из стандарта:
Указатель возвращается, если выделение успешно выполнено соответствующим образом выровнено так, чтобы что он может быть назначен указателю на любой тип объекта с фундаментальное требование выравнивания, а затем используется для доступа к такому объекта или массива таких объектов в выделенном пространстве (до пространство явно освобождено)
и
Логически, почему имеет значение то, что сама граница адреса делится на
Из-за работы базового компьютера доступ к неуравновешенным данным может быть более дорогим (например, x86) или незаконным (например, рукой). Это позволяет аппаратным средствам использовать ярлыки, которые повышают производительность/упрощают реализацию.
Ответ 2
Во многих процессорах данные, которые не выровнены, вызовут "ловушку" или "исключение" (это другая форма исключения, чем те, что поняты компилятору С++. Даже на процессорах, которые не ловутся, когда данные не являются 't выровнен, он, как правило, медленнее (в два раза медленнее, например), когда данные не правильно выровнены. Поэтому в библиотеке компилятора/среды выполнения наилучшим образом интересны, чтобы все было хорошо выровнено.
И, кстати, malloc
(обычно) не знает, что вы выделяете. Insteat, malloc
выровнят ВСЕ данные, независимо от их размера, к некоторой подходящей границе, которая "достаточно хороша" для общего доступа к данным - обычно 8 или 16 байтов в современных комбинациях ОС/процессоров, 4 байта в старых системах,
Это связано с тем, что malloc
не знает, выполняете ли вы char* p = malloc(1000);
или double* p = malloc(1000);
, поэтому он должен предположить, что вы храните double
или что-то другое - это элемент с наибольшим требованием выравнивания.
Ответ 3
Важность выравнивания - это не проблема языка, а проблема с оборудованием. Некоторые машины неспособны считывать значение данных, которое неправильно выровнено. Другие могут это сделать, но сделать это менее эффективно, например, потребовать, чтобы два чтения считывали одно несогласованное значение.
Ответ 4
Цитата книги неверна; память, возвращаемая malloc
, гарантированно будет правильно выровнена для любого типа. Даже если вы пишете char *ch = malloc(37);
, он по-прежнему выровнен для int
или любого другого типа.
Кажется, вы спрашиваете: "Что такое выравнивание?" Если это так, есть несколько вопросов о SO об этом уже, например. здесь, или хорошее объяснение от IBM здесь.
Ответ 5
Это зависит от оборудования. Даже если int
- 32 бита, malloc(sizeof(int))
может вернуть адрес, делящийся на 1, 2 или 4. Различные процессоры обрабатывают неравномерный доступ по-разному.
Процессоры больше не читают напрямую из ОЗУ, что слишком медленно (требуется сотни циклов). Поэтому, когда они захватывают ОЗУ, они захватывают его в больших кусках, как 64 байта за раз. Если ваш адрес не выровнен, целое число в 4 байта может охватывать две 64-байтовые строки кэша, поэтому ваш процессор должен выполнить две нагрузки и исправить результат. Или, может быть, инженеры решили, что создание аппаратного обеспечения для устранения неуравновешенных нагрузок не требуется, поэтому процессор сигнализирует об исключении: либо ваша программа выйдет из строя, либо операционная система поймает исключение и исправит операцию (сотни потраченных впустую циклов).
Выравнивание адресов означает, что ваша программа отлично работает с оборудованием.
Ответ 6
Потому что это быстрее; Большинство процессоров любят данные, которые выровнены. Даже, некоторые процессоры НЕ МОГУТ получить доступ к данным, которые не выровнены! (Если вы попытаетесь получить доступ к этим данным, процессор может возникнуть сбой)