Malloc резервирует больше места, выделяя память? - PullRequest
31 голосов
/ 22 марта 2019

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

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

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

Ответы [ 3 ]

42 голосов
/ 22 марта 2019

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

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

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

28 голосов
/ 22 марта 2019

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

Такое поведение, конечно, по веским причинам:

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

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

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

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

12 голосов
/ 22 марта 2019

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

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

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

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

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

Подробнее см. https://linux.die.net/man/3/malloc.

...