Как бесплатно узнать, сколько освободить?

288

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

  • 0
    Аналогичный вопрос: stackoverflow.com/questions/851958/… (хотя я бы сказал, что это не совсем дубликат)
  • 0
    Система друзей - это еще один способ сделать это, который может вычисляться на основе указателя, без дополнительных затрат в каждом блоке.
Показать ещё 1 комментарий
Теги:
pointers
size
free

11 ответов

285
Лучший ответ

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

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

  • 38
    К вашему сведению, например, BSD имеет malloc_size() для надежного доступа к размеру блока из указателя malloc() . Но нет надежного, портативного способа.
  • 41
    Я думаю, что важно сказать, что этот дополнительный информационный блок расположен перед возвращенным указателем.
Показать ещё 16 комментариев
105

Большинство реализаций функций распределения памяти 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 (нет необходимости объединять соседние блоки при освобождении), что особенно важно в среде, в которой мы работали.

  • 0
    @paxdiablo Означает ли это, что malloc не выделяет смежные блоки памяти?
  • 2
    @ user10678, единственное реальное требование malloc состоит в том, что он дает для успешного случая блок памяти, по крайней мере, такой же большой, как и то, что вы просили. Отдельные блоки являются смежными с точки зрения того, как вы получаете доступ к элементам внутри них, но нет требования, чтобы арены, из которых происходят блоки, были смежными.
45

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

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

  • 0
    Это не ответ. Вопрос как раз в этом: почему можно свободно и надежно искать размер блока, но пока программисту не доступна такая функция?
  • 0
    Это действительно деталь реализации для API Malloc, и нет API, чтобы вернуть эту информацию стандартным способом (насколько мне известно). «Система» записывает это и использует это free . Возможно, ответ вас не удовлетворит, но я не думаю, что вы получите ответ с более общей информацией :-)
6

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


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

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

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

  • 0
    Я изменил значение указателя, возвращаемого вызовом malloc. И я освободил его без ошибок. Зачем? Смотрите здесь: stackoverflow.com/questions/42618390/…
3

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

3

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

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

  • 2
    Они действительно зависят от библиотеки (обычно это библиотека C, которая обычно очень тесно связана с ОС). Для компилятора они просто функции.
  • 1
    магические функции сладостей и радости и радости тем не менее
2

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

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

  • 3
    Это одна из возможных реализаций, но можно было бы разработать систему, в которой вся память отслеживается в одной таблице на совершенно другой странице, необязательно где-нибудь близко к пулу памяти, из которого выделяется.
1

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

void free (void * ptr);

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

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

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

1

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

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

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

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

1

Чтобы ответить на вторую половину вопроса: да, вы можете, и довольно общий шаблон в 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;
  • 0
    Это метод, совершенно отличающийся от того, который использует BSD malloc для небольших объектов (хотя это совершенно хороший метод для создания массивов в стиле Pascal)
  • 0
    И, конечно, вы могли бы использовать VLA от C99.
0

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню