Сколько памяти занимает ваша программа? (FastMM против Borland MM) - PullRequest
2 голосов
/ 21 декабря 2010

Недавно я видел странное поведение в моей программе. После создания большого количества объектов (500 МБ ОЗУ) и их освобождения объем памяти программы не возвращается к своему первоначальному размеру. Это все еще показывает след 160 МБ (Частный рабочий набор).

Нормальное поведение?

Менеджер памяти Borland не ведет себя так, поэтому, если возможно, пожалуйста, подтвердите (или подтвердите), что это нормальное поведение для FastMM: если у вас есть удобная программа, в которой вы создаете довольно сложный дочерний объект MDI (содержащий несколько элементов управления / объектов) ), можете ли вы создать в цикле 250 экземпляров этого потомка MDI в памяти (одновременно), затем освободить их все и проверить объем памяти. Пожалуйста, убедитесь, что вы используете не менее 200-300 МБ или ОЗУ с этими дочерними элементами MDI.

Особенно те, которые все еще используют Delphi 7, могут увидеть разницу, временно отключив FastMM.

Спасибо


Если кому-то интересно, особенно если вам нужны доказательства, это не утечка памяти (надеюсь, это не утечка памяти в моем коде - это тоже один из пунктов этого поста: проверить, является ли это моим вина), вот оригинальные обсуждения:

Моя программа никогда не освобождает память обратно. Почему?
Как убедить диспетчер памяти освободить неиспользуемую память

Ответы [ 5 ]

2 голосов
/ 27 декабря 2010

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

Давайте уточним некоторые вещи.Управление памятью 101. Пожалуйста, внимательно прочитайте.

При выделении памяти в Delphi задействуются два менеджера памяти.

Менеджер системной памяти

Первый - менеджер системной памяти,Он встроен в Windows и дает память в страницах размером 4 КБ.

Но он не всегда дает вам память в ОЗУ (или физическую память).Ваши данные могут храниться на жестком диске и считываться каждый раз, когда вам необходим доступ к ним.Это очень медленно.

Другими словами, представьте, что у вас 512 МБ физической памяти.Вы запускаете две программы, каждая из которых запрашивает 1 ГБ памяти.Что делает ОС?

Она удовлетворяет оба запроса.Оба приложения получают по 1 ГБ памяти.Оба думают, что вся память «в памяти».Но на самом деле в оперативной памяти можно хранить только 512 Мб.Остальное хранится в файле подкачки, хотя ваше приложение этого не знает.Это просто работает медленно.

Размер рабочего набора

Теперь, какой «размер рабочего набора» вы измеряете?

Это часть выделенной памяти, которая сохраняетсяв ОЗУ.

Если у вас есть приложение, которое выделяет 1 ГБ памяти, и у вас есть только 512 МБ ОЗУ, то размер рабочего набора будет 512 МБ.Хотя он «использует» 1 ГБ памяти!

Когда вы запускаете другое приложение, которому требуется память, ОС автоматически освобождает часть ОЗУ, перемещая редко используемые блоки «памяти» на жесткий диск.

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

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

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

TLDR : «Размер рабочего набора» не означает «сколько памяти использует приложение».Это "сколько готово прямо сейчас".Не пытайтесь свести его к минимуму, вы только усугубляете ситуацию.

Диспетчер памяти Delphi

ОС предоставляет вам виртуальную память на страницах по 4 КБ.Но часто вам это нужно в гораздо меньших порциях.Например, 4 байта для вашего целого числа или 32 байта для некоторой структуры.Решение?

Менеджер памяти приложений, такой как FastMM или BorlandMM или др.

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

Другими словами, когда вы запрашиваете 14 байтов памяти, вот что происходит:

  1. Вы запрашиваете у FastMM 14 байтов памяти.
  2. FastMM запрашивает у ОС 1 страницу памяти (4096 байт).
  3. ОС выделяет одну страницу памяти, резервируя ее с помощью ОЗУ (она хранится в реальном ОЗУ).
  4. FastMM сохраняет эту страницу, обрезает 14 байт и выдает вам.

Когда вы запрашиваете еще 14 байт, FastMM просто обрезает еще 14 байт с той же страницы.

Что происходит, когда вы освобождаетеобъем памяти?То же самое в обратном направлении:

  1. Вы освобождаете 14 байтов для FastMM.Ничего не происходит.
  2. Вы освобождаете еще 14 байтов.FastMM видит, что выделенная им 4096-байтовая страница теперь полностью не используется.
  3. Поэтому она освобождает страницу, возвращая ее в систему.

Стоит отметить, что FastMM не может освободить только 14 байт для системы.Это должно освободить память в страницах.Пока вся страница не будет свободной, FastMM не сможет ничего сделать.Никто не может.

Итак, почему размер моего рабочего набора такой большой, хотя я все выпустил?

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

В чем проблема? Вы должны быть в состоянии понять это.

Допустим, вы выделяете 1 КБ, а затем 3 КБ памяти. Сколько виртуальной памяти вы выделили? 4кб, 1 стр.

Теперь вы выпускаете 3Kb. Сколько виртуальной памяти вы используете сейчас? 1Kb? Нет, это все еще 1 страница. Вы не можете выделить менее 1 страницы из системы. Вы все еще используете 4096 байт виртуальной памяти.

Представьте, если вы сделаете это 1000 раз. 1 КБ, 3 КБ, 1 КБ, 3 КБ, 1 КБ, 3 КБ и так далее. Вы выделяете 1000 * 4kb = 4 МБ, а затем освобождаете все части по 3 КБ. Сколько виртуальной памяти вы используете сейчас?

Еще 4 мб. Потому что сначала вы выделили 1000 страниц. Из каждой страницы вы взяли куски 1 КБ и 3 КБ. Даже если вы освободите блоки размером 3 КБ, блоки размером 1 КБ будут продолжать сохранять каждую страницу, выделенную вами, в памяти. И каждая страница занимает 4 КБ виртуальной памяти.

Менеджер памяти не может волшебным образом "переместить" все ваши куски по 1 КБ вместе. Это невозможно, потому что на их виртуальные адреса можно ссылаться откуда-то в коде. Это не черта FastMM.

Но почему с BorlandMM все работает лучше?

Совпадение. Может быть, так получилось, что BorlandMM дает вам память немного иначе, чем FastMM. Следующее, что вы знаете, вы что-то изменили в своем приложении, и BorlandMM работает так же, как FastMM. Диспетчер памяти не может полностью предотвратить этот эффект, который называется фрагментацией памяти.

Так что мне делать?

Короткий ответ: не так много, пока это вас не беспокоит.

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

И «лишняя» память не теряется. Хотя страницы распределены, 3 КБ каждого помечается как «свободный». В следующий раз, когда вашему приложению понадобится память, диспетчер памяти будет использовать это пространство.

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

Как это: 1kb, 1kb, 1kb, ..., 3kb, 3kb, 3kb ...

Если вы сейчас освободите все блоки по 3 КБ, ваше потребление виртуальной памяти значительно снизится.

Это не всегда возможно. Если это невозможно, то просто ничего не делай. Это более или менее хорошо, как это.

И П.С.

Во-первых, вам не следует выделять 500 форм. Это явно не путь. Исправьте это, и вам даже не нужно будет думать о распределении и освобождении памяти.

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

2 голосов
/ 21 декабря 2010

Inirming: Delphi 2007, менеджер памяти по умолчанию (должен быть вариантом FastMM).Несколько тестов на тяжелых объектах:

  1. Начальная память 2 МБ, пиковая память 30 МБ, конечная память 4 МБ.
  2. Начальная память 2 МБ, максимальная память 1 ГБ, конечная память 5,5 МБ.
2 голосов
/ 21 декабря 2010

IIRC, диспетчер памяти Delphi не сразу возвращает свободную память в ОС.

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

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

1 голос
/ 27 декабря 2010

решаемые

Чтобы подтвердить, что это поведение генерируется FastMM (как предложено Барри Келли), я создал вторую программу, которая выделяла МНОГО ОЗУ. Как только Windows исчерпала ОЗУ, использование памяти моей программы вернулось к своему первоначальному значению.

Проблема решена. Особая благодарность Барри Келли, единственному человеку, который указал на настоящую «проблему».

1 голос
/ 21 декабря 2010

Какова статистика heapmanager (GetHeapStatus) на тот момент, что 160 МБ еще выделено?

...