Большинство реализаций функций распределения памяти C хранят учетную информацию для каждого блока, встроенного или отдельно.
Один из типичных способов (встроенный) состоит в том, чтобы фактически выделить и заголовок, и запрошенную память, заполненную до некоторого минимального размера. Так, например, если вы запросили 20 байтов, система может выделить 48-байтовый блок:
Указанный вам адрес является адресом области данных.Затем, когда вы освободите блок, free
просто возьмет адрес, который вы ему даете, и, если вы не заполнили этот адрес или память вокруг него, проверит учетную информацию непосредственно перед ним.
Имейте в виду, что размер заголовка и заполнения полностью определяется реализацией (на самом деле, все это определяется реализацией a , но опция inline-Accounting-info является общей).
Контрольные суммы и специальные маркеры, которые существуют в учетной информации, часто являются причиной ошибок типа «Память повреждена», если вы их перезаписываете. Заполнение (чтобы сделать распределение более эффективным) - вот почему вы иногда можете написать немного за пределами запрошенного пространства, не вызывая проблем (тем не менее, не делайте этого, это поведение undefined и, только потому, что оно иногда работает, не работает » означает, что это нормально).
a Я написал реализации malloc
во встроенных системах, где у вас было 128 байтов независимо от того, что вы запрашивали (это был размер самой большой структуры в системе) и простой Не встроенная битовая маска использовалась, чтобы решить, был ли выделен 128-байтовый блок или нет.
У других, которые я разработал, были разные пулы для 16-байтовых фрагментов, 64-байтовых фрагментов, 256-байтовых фрагментов и 1 КБ фрагментов, опять же с использованием битовой маски, чтобы уменьшить накладные расходы на учетную информацию и увеличить скорость malloc
и free
(нет необходимости объединять смежные свободные блоки), что особенно важно в среде, в которой мы работали.
Когда вы выделяете блок памяти, выделяется больше байт, чем вы запросили. Сколько именно, зависит от реализации, но вот пример:
struct MallocHeader {
struct MallocHeader * prev, * next;
size_t length;
... more data, padding, etc ...
char data[0];
}
Когда malloc()
выделяет память из свободного списка, он выделит size + sizeof(struct MallocHeader)
и вернет адрес data
. В free()
смещение data
в struct MallocHeader
вычитается из переданного указателя, после чего становится известен размер.
Это зависит от реализации - это зависит от реализации libc, а также от реализации операционной системы (подробнее о реализации операционной системы).
У меня нет необходимости знать такие вещи, но если вы действительно хотите, вы можете создать свой собственный распределитель памяти.
По ошибке я обнаружил, что в C++ при выделении с помощью оператора new[] хранится количество элементов в начале выделяемой зоны, возвращая пользователю зону после количества элементов (На Visual Studio).
new[NUMBER] ---> [NUMBER (4bytes)]+[allocated area]
it returns the pointer to the allocated area
and probably when the delete[] operator is called
it looks 4 bytes before the [allocated area] to see
how much elements will be deleted
Это зависит от реализации. Куча хранит эти данные таким образом, чтобы облегчить доступ к ней с указателем, возвращаемым malloc ()
- например, в блоке может храниться количество байтов в начале и malloc ()
] вернет смещенный указатель.