Позволяет ли освобождать или удалять освобождение памяти обратно в "систему",

Здесь мой вопрос: освобождает ли звонок или удаляет когда-либо выпуск памяти обратно в "систему". По системе я имею в виду, он когда-либо уменьшает сегмент данных процесса?

Давайте рассмотрим распределитель памяти в Linux, т.е. ptmalloc.

Из того, что я знаю (пожалуйста, поправьте меня, если я ошибаюсь), ptmalloc поддерживает свободный список блоков памяти, и когда приходит запрос на распределение памяти, он пытается выделить блок памяти из этого бесплатного списка (я знаю, распределитель намного сложнее, но я просто помещаю его в простые слова). Если, однако, он не работает, он получает память из системы, используя системные вызовы sbrk или brk. Когда память свободна, этот блок помещается в свободный список.

Теперь рассмотрим этот сценарий, при пиковой нагрузке на кучу выделено много объектов. Теперь, когда нагрузка уменьшается, объекты свободны. Поэтому мой вопрос: после того, как объект свободен, распределитель выполнит некоторые вычисления, чтобы определить, следует ли просто сохранить этот объект в свободном списке или в зависимости от текущего размера бесплатного списка, он может решить вернуть эту память обратно система, то есть уменьшить сегмент данных процесса, используя sbrk или brk.

Документация glibc говорит мне, что если запрос на распределение намного больше размера страницы, он будет выделен с помощью mmap и будет сразу выпущен обратно в систему после free'd. Круто. Но скажем, я никогда не прошу выделить размер больше, чем 50 байтов, и я задаю много таких 50 байтовых объектов при максимальной нагрузке на систему. Тогда что?

Из того, что я знаю (верьте мне, пожалуйста), память, выделенная malloc, никогда не будет выпущена обратно в систему до тех пор, пока процесс не закончится. Если распределитель просто сохранит его в свободном списке, если я его освобожу. Но вопрос, который беспокоит меня, заключается в том, что если я использую инструмент для просмотра использования памяти в моем процессе (я использую pmap в Linux, что вы, ребята, используете?), Он должен всегда показывать память, используемую при максимальной нагрузке ( поскольку память никогда не возвращается в систему, кроме случаев, когда она назначается с помощью mmap)? Это память, используемая процессом, никогда не должна уменьшаться (кроме памяти стека)? Это?

Я знаю, что чего-то не хватает, поэтому прошу пролить свет на все это.

Эксперты, пожалуйста, очистите мои концепции относительно этого. Я буду благодарен. Надеюсь, я смог объяснить свой вопрос.

Спасибо всем за ваше терпение.

Отношения Lali

Ответ 1

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

Для вашей конкретной реализации нет причин для free(), поскольку malloc не будет выпускаться в системную память, и поэтому он освободит память только к вашему собственному распределителю.

Другой причиной использования настраиваемого распределителя является то, что вы можете выделять много объектов одинакового размера (т.е. у вас есть некоторая структура данных, которую вы выделяете много). Вы можете захотеть сохранить отдельный бесплатный список для этого типа объекта и бесплатно/выделить только из этого специального списка. Преимущество этого заключается в том, что это позволит избежать фрагментации памяти.

Ответ 2

Он полностью зависит от реализации. В Windows VС++ программы могут возвращать память обратно в систему, если на соответствующих страницах памяти есть только свободные блоки.

Ответ 3

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

Это относится только к вашей текущей системе (т.е. на основе предоставленной документации бесплатно и mmap и malloc), но, как заявил предыдущий плакат, их поведение зависит от имплантации.

Ответ 4

Я считаю, что распределитель памяти в glibc может вернуть память обратно в систему, но зависит от того, будет или нет это зависит от ваших шаблонов распределения памяти.

Скажем, вы делаете что-то вроде этого:

void *pointers[10000];
for(i = 0; i < 10000; i++)
    pointers[i] = malloc(1024);
for(i = 0; i < 9999; i++)
    free(pointers[i]);

Единственная часть кучи, которую можно безопасно вернуть в систему, - это "кусок пустыни", который находится в конце кучи. Это может быть возвращено системе с использованием другого системного вызова sbrk, и распределитель памяти glibc будет делать это, когда размер этого последнего блока превышает некоторый порог.

Вышеуказанная программа сделает 10000 небольших распределений, но только освободит первые 9999 из них. Последний должен (предполагая, что ничто другое не вызвало malloc, что маловероятно) сидеть прямо в конце кучи. Это предотвратило бы, чтобы распределитель вообще не возвращал любую память в систему.

Если вы хотите освободить оставшееся распределение, реализация glibc malloc должна вернуть большинство страниц, которые были возвращены системе.

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

Ответ 5

Нет.


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

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

  • Требуется вызов ядра, и вызовы ядра медленны, поэтому это замедляет работу программа. Это намного быстрее, чтобы просто выбросить блок в кучу.

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

Ответ 6

Это немного отличается от реализации до реализации.

Подумайте о своей памяти как о массивном длинном блоке, когда вы выделите ее, вы немного уберетесь от своей памяти (помечено "1" ниже):

111

Если я выделяю больше памяти с помощью malloc, он получает некоторые из системы:

1112222

Если теперь я освобожу '1':

___2222

Он не будет возвращен системе, потому что два перед ним (а память задана как непрерывный блок). Однако, если конец памяти освобожден, тогда эта память возвращается в систему. Если бы я освободил "2" вместо "1". Я бы получил:

111

бит, где "2" был возвращен в систему. Основное преимущество освобождения памяти заключается в том, что этот бит можно перераспределить, а не получать больше памяти из системы. например:

33_2222

Ответ 7

Вот некоторые "преимущества" для того, чтобы никогда не выпускать память обратно в систему:

  • Имея уже много памяти, очень вероятно, что вы снова это сделаете, и
    • При выпуске памяти операционная система должна выполнять довольно много документов
    • когда вам это нужно снова, ваш распределитель памяти должен повторно инициализировать все свои структуры данных в области, которую он только что получил.
  • Свободная память, которая не нужна, выгружается на диск, где она на самом деле не имеет такой большой разницы.
  • Часто, даже если вы освобождаете 90% своей памяти, фрагментация означает, что очень мало страниц может быть действительно выпущено, поэтому усилия, необходимые для поиска пустых страниц, не очень хорошо потрачены.

Ответ 8

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

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

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