Как убедить менеджер памяти освободить неиспользуемую память - PullRequest
5 голосов
/ 18 декабря 2010

В недавнем сообщении ( Моя программа никогда не освобождает память обратно. Почему? ) Я показываю, что при использовании FastMM приложение не высвобождает значительные объемы памяти обратно в систему.Недавно я создал программу искусственного тестирования, чтобы убедиться, что проблема не в памяти, а в том, что она появляется только с FastMM.

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

Требования к памяти («Частный рабочий набор»):

Без FastMM
Перед запуском цикла: 1,2 МБ
После запуска цикла: 2,1 МБ

С FastMM (агрессивный режим отладки)
Перед запуском циклацикл: 2,1 МБ
После запуска цикла: 25 МБ

С FastMM (режим разблокировки)
До запуска цикла: 1,8 МБ
После запуска цикла: 3 МБ

Если я запускаю цикл несколько раз, требования к памяти не увеличиваются.Это означает, что неизданная память используется повторно, так что это не утечка памяти (утечка памяти увеличит объем памяти на несколько КБ / МБ при каждом запуске).


Мои вопросы:

Как отключить это поведение в FastMM?Это вообще возможно?Я знаю, что если я выпущу программу без FastMM или с FastMM Release Mode, она будет «тратить» умеренное количество оперативной памяти.Но отключение этого поведения по требованию поможет мне (нам?) Выявить утечки памяти.На самом деле в моем первом посте (см. Ссылку) многие люди предположили, что у меня есть утечка.Беспорядок был создан, очевидно, только из-за этого поведения.Нет, очевидно, что утечки нет.Это просто диспетчер памяти, который отказывается освобождать большие объемы памяти.

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

Ответы [ 4 ]

11 голосов
/ 18 декабря 2010

Вы не должны думать об этом, как об «потере» ОЗУ, правда.Думайте об этом как о «кешировании» неиспользуемой оперативной памяти.Диспетчер памяти удерживает неиспользуемую память вместо того, чтобы по какой-то причине возвращать ее обратно в ОС, и фактически вы столкнулись с этой причиной в своем вопросе.те же операции в цикле.Когда вы делаете это, у него все еще остается старая доступная память, и он может назначить ее немедленно, вместо того, чтобы запрашивать у Windows новый кусок кучи.Это один из приемов, который ставит «Fast» в «FastMM», и если этого не произойдет, ваша программа будет работать намного медленнее.

Вам не нужно беспокоитьсяо рисунке режима отладки FastMM.Это только для отладки, и вы не собираетесь выпускать программу, скомпилированную с FullDebugMode.И разница между «без FastMM» и «с FastMM Release Mode» составляет около 1 МБ, что незначительно на современном оборудовании.При низкой стоимости всего в 1 МБ вы получаете значительное повышение производительности.Так что не беспокойся об этом.

9 голосов
/ 18 декабря 2010

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

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

Другой вариант - перенаправить все в кучу ОС.Используйте HeapAlloc.Вы даже можете включить кучу с низкой фрагментацией для своей программы (по умолчанию в Windows Vista), что заставит ОС использовать стратегию, аналогичную стратегии FastMM, но позволит вамиспользуйте некоторые средства отладки и анализа от Microsoft, чтобы отслеживать использование памяти вашей программой с течением времени.Однако помните, что после вызова HeapFree некоторые метрики могут по-прежнему отображать память как принадлежащую вашей программе.

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

3 голосов
/ 18 декабря 2010

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

unit msvcrtMM;

interface

implementation

type
  size_t = Cardinal;

const
  msvcrtDLL = 'msvcrt.dll';

function malloc(Size: size_t): Pointer; cdecl; external msvcrtDLL;
function realloc(P: Pointer; Size: size_t): Pointer; cdecl; external msvcrtDLL;
procedure free(P: Pointer); cdecl; external msvcrtDLL;

function GetMem(Size: Integer): Pointer;
begin
  Result := malloc(size);
end;

function FreeMem(P: Pointer): Integer;
begin
  free(P);
  Result := 0;
end;

function ReallocMem(P: Pointer; Size: Integer): Pointer;
begin
  Result := realloc(P, Size);
end;

function AllocMem(Size: Cardinal): Pointer;
begin
  Result := GetMem(Size);
  if Assigned(Result) then begin
    FillChar(Result^, Size, 0);
  end;
end;

function RegisterUnregisterExpectedMemoryLeak(P: Pointer): Boolean;
begin
  Result := False;
end;

const
  MemoryManager: TMemoryManagerEx = (
    GetMem: GetMem;
    FreeMem: FreeMem;
    ReallocMem: ReallocMem;
    AllocMem: AllocMem;
    RegisterExpectedMemoryLeak: RegisterUnregisterExpectedMemoryLeak;
    UnregisterExpectedMemoryLeak: RegisterUnregisterExpectedMemoryLeak
  );

initialization
  SetMemoryManager(MemoryManager);

end.

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

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

решено

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

Проблема решена.Спасибо, Барри.

...