Можно ли очистить память? - PullRequest
30 голосов
/ 09 января 2010

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

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

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

Ответы [ 7 ]

73 голосов
/ 09 января 2010

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

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

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

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

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

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

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

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

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

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

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

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

О SetProcessWorkingSetSize:

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

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

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

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

17 голосов
/ 09 января 2010

Это то, что мы используем в 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 }
5 голосов
/ 09 января 2010

Давайте разберемся: FastMM4 не пропускает память, ваш код может.

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

ReportMemoryLeaksOnShutdown := True;

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

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

3 голосов
/ 09 января 2010

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

2 голосов
/ 09 января 2010

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

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

0 голосов
/ 08 апреля 2010

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

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

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

0 голосов
/ 09 января 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...