Как бесплатно знать, сколько бесплатно?

В программировании на языке C вы можете передать любой вид указателя, который вам нравится, в качестве аргумента для бесплатной загрузки, как он знает, какой размер выделенной памяти свободен? Всякий раз, когда я передаю указатель на какую-то функцию, я должен также передавать размер (т.е. Массив из 10 элементов должен получать 10 в качестве параметра, чтобы знать размер массива), но мне не нужно передавать размер бесплатная функция. Почему бы и нет, и могу ли я использовать эту же технику в своих собственных функциях, чтобы избавить меня от необходимости привязывать к дополнительной переменной длины массива?

Ответ 1

Когда вы вызываете malloc(), вы указываете объем памяти для выделения. Объем используемой памяти немного больше, чем этот, и включает дополнительную информацию, которая записывает (по крайней мере), насколько велик блок. Вы не можете (надежно) получить доступ к этой другой информации - и не должны: -).

Когда вы вызываете free(), он просто просматривает дополнительную информацию, чтобы узнать, насколько велик блок.

Ответ 2

Большинство реализаций функций распределения памяти C будут хранить учетную информацию для каждого блока, как в строке, так и отдельно.

Один типичный способ (в строке) - фактически распределить как заголовок, так и запрошенную память, дополненный минимальным размером. Например, если вы запросили 20 байтов, система может выделить 48-байтовый блок:

  • 16-байтовый заголовок, содержащий размер, специальный маркер, контрольную сумму, указатели на следующий/предыдущий блок и т.д.
  • область данных размером 32 байта (ваши 20 байт заполнены до кратного 16).

Адрес, указанный вами, является адресом области данных. Затем, когда вы освободите блок, free просто возьмет адрес, который вы ему даете, и, предположив, что вы не наполнили этот адрес или память вокруг него, проверьте учетную информацию непосредственно перед этим. Графически это будет выглядеть так:

 ____ The allocated block ____
/                             \
+--------+--------------------+
| Header | Your data area ... |
+--------+--------------------+
          ^
          |
          +-- The address you are given

Имейте в виду, что размер заголовка и заполнения дополнен полной реализацией (на самом деле, все это определяется реализацией (a) но встроенный метод учета является общим).

Контрольные суммы и специальные маркеры, которые существуют в учетной информации, часто являются причиной ошибок, таких как "Memory arena corrupted" или "Double free", если вы перезаписываете их или освобождаете их дважды.

Отступы (чтобы сделать распределение более эффективным) - это то, почему вы иногда можете писать немного за пределы вашего запрошенного пространства, не вызывая проблем (по-прежнему, не делайте этого, это поведение undefined и только потому, что оно иногда работает, не означает, что это нормально делать).


(a) Я написал реализации malloc во встроенных системах, где вы получили 128 байтов независимо от того, что вы просили (это был размер самой большой структуры в системе) предполагая, что вы запросили 128 байтов или меньше (запросы на большее число будут удовлетворены с возвращаемым значением NULL). Очень простая битовая маска (т.е. Не в строке) использовалась для определения того, был ли выделен 128-байтовый блок или нет.

Другие, которые я разработал, имели разные пулы для 16-байтовых блоков, 64-байтовых кусков, 256-байтовых фрагментов и 1K кусков, снова используя бит-маску, чтобы решить, какие блоки были использованы или доступны.

Оба этих параметра позволили уменьшить накладные расходы бухгалтерской информации и увеличить скорость malloc и free (нет необходимости объединять соседние блоки при освобождении), что особенно важно в среде, в которой мы работали.

Ответ 3

Из списка comp.lang.c FAQ: Как бесплатно узнать, сколько байтов бесплатно?

Функция malloc/free запоминает размер каждого блока по мере его выделения, поэтому нет необходимости напоминать размер при освобождении. (Как правило, размер хранится рядом с выделенным блоком, поэтому обычно обычно плохо ломаются, если границы выделенного блока даже немного превышены)

Ответ 4

Этот ответ перемещается из Как free() знает, сколько памяти освобождает?, где я был явно неспособен ответить на кажущийся дублирующий вопрос. Затем этот ответ должен иметь отношение к этому дубликату:


В случае malloc, распределитель кучи сохраняет отображение исходного возвращенного указателя, к соответствующим деталям, необходимым для free в памяти позже. Обычно это включает в себя сохранение размера области памяти в любой форме, относящейся к используемому распределителю, например необработанному размеру, или node в двоичном дереве, используемом для отслеживания распределений, или количестве используемых "единиц измерения" памяти.

free не сработает, если вы переименуете указатель или каким-либо образом его дублируете. Это, однако, не подсчитано, и только первая free будет правильной. Дополнительные free являются ошибками с двойной ошибкой.

Попытка free любого указателя со значением, отличным от значений, возвращаемых предыдущими malloc s, и пока еще не разрешенная ошибка. Частично не освобождаются области памяти, возвращаемые с malloc.

Ответ 5

malloc() и free() зависят от системы/компилятора, поэтому трудно дать конкретный ответ.

Дополнительная информация по этому другому вопросу.

Ответ 6

В соответствующей заметке Библиотека GLib имеет функции распределения памяти, которые не сохраняют неявный размер, - и затем вы просто передаете параметр размера бесплатно, Это может устранить часть накладных расходов.

Ответ 7

Менеджер кучи хранит объем памяти, принадлежащий выделенному блоку, где-то, когда вы вызывали malloc.

Я никогда не реализовал его сам, но я думаю, что память прямо перед выделенным блоком может содержать метаинформацию.

Ответ 8

Чтобы ответить на вторую половину вопроса: да, вы можете, и довольно общий шаблон в C следующий:

typedef struct {
    size_t numElements
    int elements[1]; /* but enough space malloced for numElements at runtime */
} IntArray_t;

#define SIZE 10
IntArray_t* myArray = malloc(sizeof(intArray_t) + SIZE * sizeof(int));
myArray->numElements = SIZE;

Ответ 9

Первоначальная техника заключалась в том, чтобы выделить немного больший блок и сохранить размер в начале, а затем предоставить приложению всю оставшуюся часть блога. Дополнительное пространство содержит размер и, возможно, ссылки для потоковой передачи свободных блоков для повторного использования.

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

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

В общем, ответ таков: для сохранения состояния выделяется отдельная структура данных.

Ответ 10

память, выделенная с помощью malloc() или calloc() или realloc().

void free (void * ptr);

свободная функция не принимает размер в качестве параметра. Как функция free() знает, сколько памяти освобождается от заданного указателя?

Ниже приведен наиболее распространенный способ хранения размера памяти, так что free() знает, какой размер памяти будет освобожден.

Когда выделение памяти выполняется, выделенное пространство кучи на одно слово больше, чем запрошенная память. Дополнительное слово используется для хранения размера выделения и позже используется функцией free()

Ответ 11

Когда мы вызываем malloc, он просто потребляет больше байта из этого требования. Это больше байтового потребления содержит информацию, такую ​​как контрольная сумма, размер и другая дополнительная информация. Когда мы звоним бесплатно в это время, он напрямую переходит к этой дополнительной информации, где он находит адрес, а также определяет, сколько блоков будет бесплатным.