Malloc резервирует больше места, выделяя память?

Я наблюдаю следующее поведение в моей тестовой программе:

Я делаю malloc() для 1 МБ и затем free() после sleep(10). Я делаю это пять раз. Я наблюдаю потребление памяти в top во время работы программы.

После free() -d я ожидаю, что потребление виртуальной памяти программы (VIRT) уменьшится на 1 МБ. Но на самом деле это не так. Он остается стабильным. Чем объясняется такое поведение? malloc() делает некоторый резерв при выделении памяти?

Ответ 1

После free() -d я ожидаю, что потребление виртуальной памяти программы (VIRT) сократится на 1 МБ.

Ну, это не гарантируется стандартом C. Он только говорит, что, как только вы free() память, вы больше не должны обращаться к ней.

Будет ли блок памяти фактически возвращен в доступный пул памяти или оставлен в стороне для будущих распределений, решается диспетчером памяти.

Ответ 2

Стандарт C не навязывает реализации malloc и может free возвращать память в ОС. Таким образом, различные реализации библиотеки C будут вести себя по-разному. Некоторые из них могут вернуть его напрямую, а некоторые нет. Фактически, одна и та же реализация будет вести себя по-разному в зависимости от размеров и шаблонов распределения.

Такое поведение, конечно, по уважительным причинам:

  1. Это не всегда возможно. Распределение памяти на уровне ОС обычно выполняется в страницах (4 КБ, 4 МБ или... размеры одновременно). И если небольшая часть страницы все еще используется после освобождения другой части, то страница не может быть возвращена операционной системе, пока эта часть также не будет освобождена.
  2. Эффективность. Весьма вероятно, что приложение снова запросит память. Так зачем возвращать его обратно в ОС, а вскоре после этого попросить снова. (конечно, возможно, существует ограничение на размер сохраняемой памяти.)

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

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

Редактировать: я не объяснил, почему вы не несете ответственности за память, которую вы свободны. Причина в том, что в современной ОС выделенная память является виртуальной. Это означает, что если вы выделите 512 МБ в 32-разрядной системе или 10 ТБ в 64-разрядной системе, если вы не читаете или не записываете в эту память, она не резервирует для нее никакого физического пространства. На самом деле, он зарезервирует физическую память только для страниц, к которым вы прикоснулись из этого большого блока, а не для всего блока. И через "некоторое время неиспользования этой памяти" ее содержимое будет скопировано на диск, а базовая физическая память будет использована для чего-то другого.

Ответ 3

Это очень зависит от фактической используемой реализации malloc.

В Linux существует пороговое значение (MMAP_THRESHOLD), позволяющее определить, откуда MMAP_THRESHOLD память для данного запроса malloc().

Если запрашиваемая сумма меньше или равна MMAP_THRESHOLD, запрос удовлетворяется либо путем извлечения его из так называемого "свободного списка", если какие-либо блоки памяти уже были free() d. В противном случае "разрыв строки" программы (т.е. Конец сегмента данных) увеличивается, и память, выделенная программе этим процессом, используется для запроса.

В free() освобожденный блок памяти добавляется в список свободных. Если в самом конце сегмента данных достаточно свободной памяти, разрывная линия (упомянутая выше) снова перемещается, чтобы уменьшить сегмент данных, возвращая избыточную память в ОС.

Если запрашиваемая сумма превышает MMAP_THRESHOLD, ОС запрашивает отдельный блок памяти и снова возвращает его во время free().

Смотрите также https://linux.die.net/man/3/malloc для деталей.