Можно ли очистить память?

29

Я работаю в Delphi 5 (с установкой FastMM) в проекте Win32 и недавно пытался резко сократить использование памяти в этом приложении. До сих пор я сократил использование почти вдвое, но заметил что-то при работе над отдельной задачей. Когда я минимизировал приложение, использование памяти сократилось с 45 мегабайт до 1 мегабайта, что я приписывал ему подкачку на диск. Когда я восстановил его и перезапустил работу, память увеличилась до 15 мегабайт. По мере того, как я продолжал работать, использование памяти медленно увеличивалось, и сведение к минимуму и восстановление сбросили его до 15 мегабайт. Поэтому, по моему мнению, когда мой код сообщает системе о выпуске памяти, ее все еще держат в соответствии с Windows, и фактическая сборка мусора не срабатывает до тех пор, пока не будет много позже.

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

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

  • 2
    +1 за странную проблему. Я вернусь к этому вопросу, чтобы увидеть ваше решение.
  • 8
    Обрезка рабочего набора - красная сельдь при исследовании утечки памяти, fwiw. Process Explorer может показать вам больше статистики, чем диспетчер задач (вам нужно выбрать все необходимые столбцы): technet.microsoft.com/en-us/sysinternals/bb896653.aspx
Показать ещё 2 комментария
Теги:
garbage-collection
memory-management

7 ответов

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

Это то, что мы используем в DSiWin32:

procedure DSiTrimWorkingSet;
var
  hProcess: THandle;
begin
  hProcess := OpenProcess(PROCESS_SET_QUOTA, false, GetCurrentProcessId);
  try
    SetProcessWorkingSetSize(hProcess, $FFFFFFFF, $FFFFFFFF);
  finally CloseHandle(hProcess); end;
end; { DSiTrimWorkingSet }
  • 0
    Я постараюсь включить это в. Спасибо за код.
  • 0
    Хорошо, это отлично подходит для обрезки памяти. Теперь, чтобы понять, как заставить его работать с более сложными областями моего кода.
Показать ещё 4 комментария
72

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

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

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

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

Если вы заинтересованы в использовании памяти в приложении под Windows, нет ни одного наиболее важного числа, а всего диапазона соответствующих номеров:

  • Виртуальный размер - это общий объем адресного пространства, зарезервированного приложением. Адресное пространство (то есть, какие указатели указывают) может быть безоговорочно, зарезервировано или зафиксировано. Unreserved память может быть выделена в будущем либо менеджером памяти, либо путем загрузки DLL (библиотеки DLL должны быть куда-то в памяти) и т.д.

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

  • Совместимый рабочий набор. Это страницы рабочего набора, которые можно использовать совместно, но могут или не могут быть совместно использованы. Например, библиотеки DLL или пакеты (BPL) могут быть загружены в пространство памяти приложения. Код для этих DLL потенциально может быть разделен между несколькими процессами, но если DLL загружается только один раз в одно приложение, то он фактически не используется. Если DLL очень специфична для этого приложения, он функционально эквивалентен частному рабочему набору.

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

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

Эти числа не представляют собой непересекающиеся множества. Это разные способы суммирования состояний разных типов страниц. Например, рабочий набор= персональный рабочий набор + совлокальный рабочий набор.

Какое из этих чисел наиболее важно, зависит от того, с чем вы ограничены. Если вы пытались выполнять ввод-вывод с использованием файлов с отображением памяти, виртуальный размер ограничивает объем памяти, которую вы можете посвятить сопоставлению. Если вы находитесь в среде с ограниченной физической памятью, вы хотите свести к минимуму рабочий набор. Если у вас много разных экземпляров приложения одновременно, вы хотите минимизировать личные байты и максимизировать общие байты. Если вы создаете множество разных DLL и BPL, вы должны быть уверены, что они фактически разделены, убедившись, что их адреса загрузки не приводят к конфликту и предотвращению совместного использования.

О SetProcessWorkingSetSize:

Windows обычно обрабатывает рабочий набор автоматически, в зависимости от давления памяти. Рабочий набор не определяет, удастся ли вам выполнить ошибку с ошибкой (OOM). Рабочий набор, используемый для принятия решений о пейджинге, то есть, что нужно хранить в памяти и что оставить на диске (в случае DLL) или вывести на диск (другая зафиксированная память). Он не будет иметь никакого эффекта, если в системе больше виртуальной памяти, чем физическая память.

Что касается его эффектов: если нижняя граница установлена ​​на высокий уровень, это означает, что процесс будет враждебен другим приложениям и попытаться воспроизвести память в ситуациях физического давления памяти. Это одна из причин, почему для этого требуется защитное право PROCESS_SET_QUOTA.

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

В большинстве ситуаций вы не хотите изменять детали рабочего набора. Обычно лучше всего позволить ОС справиться с этим. Это не помешает ситуациям OOM. Обычно это вызвано исчерпанием адресного пространства, поскольку диспетчер памяти не мог зафиксировать больше памяти; или в системах с недостаточным файловым пространством страницы для резервного копирования виртуальной памяти, когда пробел в файле страницы заканчивается.

  • 1
    Барри, это отличная информация, которая помогла мне понять это. Благодарю. Один дополнительный вопрос, связанный с оригиналом: могу ли я сказать Windows обрезать рабочий набор по требованию? Из ссылки fupsduck, прикрепленной к его ответу, похоже, что это то, что делает команда?
  • 15
    Барри, у тебя есть реальная способность объяснять сложные темы. Вы должны опубликовать это в своем блоге, так что у нас будет место, куда можно отсылать людей в будущем, когда они будут спрашивать о памяти процесса. Небеса знают, что такого рода вопросы возникают достаточно!
Показать ещё 3 комментария
5

Позвольте получить это прямо: FastMM4 не утечка памяти, ваш код может.

Чтобы точно знать, выполните эту инструкцию где-то в своем приложении (где FastMM4 находится в предложении uses и $define ManualLeakReportingControl установлено, например, в FastMM4Options.inc):

ReportMemoryLeaksOnShutdown := True;

FastMM4 будет сообщать в конце, если вы забыли освободить некоторую память.

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

  • 0
    Я определенно не буду оспаривать вас. Я кодер номер 4 в этой партии кода и все еще пытаюсь выяснить, почему некоторые вещи были сделаны такими, какими они были. В этом коде наверняка много проблем с памятью. Я использовал возможности создания отчетов FastMM, а также Pascal Analyzer и QATime, чтобы как можно больше исследовать этот код, поэтому я знаю, что я устранил многие проблемы.
  • 0
    Теперь, если вы уверены, что FastMM4 не сообщает об утечке памяти, если вы работаете в Vista, Windows2008 или Windows 7, в ОС возникают проблемы с памятью , поскольку критические разделы сохраняют в кеше структуру отладки, а ADO каждый раз выдает утечку памяти. установить ConnectionString.
Показать ещё 1 комментарий
3

Получив отличный ответ от Барри Келли, попробуйте проанализировать свой процесс с помощью VMMap из Sysinternals, который можно найти здесь. Это анализирует использование памяти одного процесса более подробно, чем Process Explorer: "VMMap - идеальный инструмент для разработчиков, которые хотят понимать и оптимизировать использование ресурсов памяти приложений". Он также имеет полезный файл справки.

  • 0
    +1 за упоминание VMMap
2

Диспетчер задач не показывает, что использует ваша программа. Он показывает общее количество, которое диспетчер памяти выделил из Windows. Когда вы освобождаете объект или иным образом освобождаете динамически выделенную память, он немедленно возвращается в диспетчер памяти (FastMM). Независимо от того, прошло ли это обратно в Windows, другое дело. Менеджер памяти любит держать вокруг себя лишнюю память, поэтому ей не нужно захватывать больше из ОС каждый раз, когда вам нужно создать новый объект. (Это хорошо, и вы не хотите его менять.)

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

  • 0
    Да, я занимался уборкой всю неделю и следил за тем, чтобы все было освобождено должным образом. Одна вещь, которую я обнаружил два дня назад (я только 3-й год как профессиональный программист), состоит в том, что некоторые типы указателей (TStringList и т. Д.) Не освобождают объекты, прикрепленные к ним, поэтому я пытался очистить все в этом роде. Это значительно сократило размер моего следа, но оно все еще растет и не будет плато. Я подозреваю, что FastMM не возвращает Windows должным образом, но я не уверен в этом сейчас. Буду смотреть его с другим приложением монитора.
  • 0
    В отличие от многих классов VCL TStringLists нужно создавать и уничтожать явно, используя new и delete.
Показать ещё 4 комментария
0

Я читал об этом раньше, но не имею прямого опыта. Вызов WINAPI SetProcessWorkingSetSize() должен "исправить" проблему. Снова у меня нет прямого опыта с этим.

  • 0
    Из описания в MSDN, это может быть интересным упражнением (безрезультатно или нет, я не знаю), чтобы попытаться использовать get, а затем set для принудительного обновления.
  • 1
    Я просмотрел свой архив. Я думаю, что именно здесь я увидел информацию: delphi.about.com/od/windowsshellapi/ss/…
Показать ещё 2 комментария
-1

Недавно у меня была очень похожая проблема с моей программой. См. Мой вопрос: Почему память моих программ Delphi продолжает расти?

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

Прежде чем делать что-либо еще, будьте абсолютно уверены, что вы правильно освобождаете всю память.

Ещё вопросы

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