Как правило, - это потерянное пространство в заголовке блока выделенной области. Многие реализации, которые я видел, используют 16-байтовый (я использую здесь классическое определение байта, один из восьми битов, а не определение ISO C), непосредственно перед возвращением адреса из malloc
, и добавляем выделенная область до 16 байтов в конце.
Это значительно упрощает алгоритмы, используемые для выделения, а также гарантирует, что возвращаемые адреса памяти будут выровнены соответствующим образом для архитектуры.
Но имейте в виду, что это деталь реализации, а не особенность стандарта C. Если нет требований к выравниванию, а выделение памяти ограничено 255 байтами, вполне вероятно, что будет потрачен только один байт (хотя и за счет более сложного алгоритма).
Вполне вероятно, что у вас могло бы быть встроенное приложение, которое когда-либо выделяло бы только 256-байтовые чанки, и в этом случае вы могли бы иметь простой распределитель на основе растровых изображений (с растровым изображением, хранящимся в другом месте, а не в соответствии с выделенными блоками памяти). ), тратя впустую только один бит на чанк (мы делали это раньше в средах с нехваткой памяти).
Или, возможно, у вас есть распределитель в большом адресном пространстве и памяти, который дает вам 4G независимо от того, что вы просите. Тогда есть нет потерь для заголовка, но, вероятно, достаточно для заполнения: -)
Или, может быть, вы получаете кусок от арены определенного размера (1-64 байта от арены A, 65-128 от арены B и так далее). Это означает, что заголовок не требуется, но все же допускается переменный размер (до максимума) и существенно меньше потерь, чем в решении 4G выше.
Итог, это зависит от реализации.
В (достаточно простой) реализации malloc
вы могли бы иметь двусвязный список «порций», которые выдает распределитель. Эти чанки состоят из заголовка и раздела данных, и, чтобы обеспечить правильное выравнивание раздела данных, заголовок должен быть на 16-байтовой границе и быть кратным 16 байтам (это для требования к 16-байтовому выравниванию). - Ваше фактическое требование может быть не таким строгим).
Кроме того, сам чанк дополняется так, что он кратен 16 байтам, так что следующий чанк также соответствующим образом выравнивается.
Это гарантирует, что раздел данных любого чанка, который является адресом, указанным вызывающей стороне malloc
, выровнен правильно.
Так что вы вполне можете получить потери в этой области. Заголовок (с 4-байтовыми целыми числами и указателями) может быть просто:
struct mhdr {
int size; // size of this block.
struct mhdr *prev; // prev chunk.
struct mhdr *next; // next chunk.
int junk; // for padding.
} tMallocHdr;
означает, что четыре из этих шестнадцати байтов будут потрачены впустую. Иногда это необходимо для удовлетворения других требований (выравнивание), и, в любом случае, вы можете использовать это пространство для других целей. Как отметил один из комментаторов, защитные байты могут использоваться для обнаружения некоторых форм повреждения арены:
struct mhdr {
int guard_bytes; // set to 0xdeadbeef to detect some corruptions.
int size; // size of this block.
struct mhdr *prev; // prev chunk.
struct mhdr *next; // next chunk.
} tMallocHdr;
И, хотя это заполнение является технически бесполезным пространством, оно становится важным, только если оно составляет значительную долю всей арены. Если вы выделяете 4 Кбайт памяти, то четыре байта потерь составляют всего лишь одну тысячную от общего размера. На самом деле, вы, как пользователь, теряете, вероятно, целые 16 байтов заголовка, так как это память, которую вы не можете использовать, поэтому она составляет около 0,39% (16 / (4096 + 16)).
Вот почему связанный список символов в malloc - очень плохая идея - вы склонны использовать для каждого отдельного символа:
- 16 байтов заголовка.
- 1 байт для символа (при условии 8-битных символов).
- 15 байтов заполнения.
Это изменит ваш показатель 0,39% на 96,9% (31 / (31 + 1)).
И, в ответ на ваш дальнейший вопрос:
Это приемлемая жертва, или я думаю об этом неправильно?
Я бы сказал, да, это приемлемо. Как правило, вы выделяете большие куски памяти, где четыре байта не будут иметь значения в общей схеме вещей. Как я уже говорил ранее, это не очень хорошее решение, если вы выделяете много мелочей, но это не общий случай использования malloc
.