Почему после освобождения памяти использование моей программы не нормализуется? - PullRequest
6 голосов
/ 15 декабря 2010

рассмотрим следующий пример приложения

program TestMemory;


{$APPTYPE CONSOLE}

uses
  PsAPI,
  Windows,
  SysUtils;

function GetUsedMemoryFastMem: cardinal;
var
    st: TMemoryManagerState;
    sb: TSmallBlockTypeState;
begin
    GetMemoryManagerState(st);
    result := st.TotalAllocatedMediumBlockSize + st.TotalAllocatedLargeBlockSize;
    for sb in st.SmallBlockTypeStates do
    begin
        result := result + sb.UseableBlockSize * sb.AllocatedBlockCount;
    end;
end;

function GetUsedMemoryWindows: longint;
var
  ProcessMemoryCounters: TProcessMemoryCounters;
begin
  Result:=0;
  ProcessMemoryCounters.cb := SizeOf(TProcessMemoryCounters);
  if GetProcessMemoryInfo(GetCurrentProcess(), @ProcessMemoryCounters, ProcessMemoryCounters.cb) then
   Result:= ProcessMemoryCounters.WorkingSetSize
  else
   RaiseLastOSError;
end;

procedure Test;
const
  Size = 1024*1024;
var
  P : Pointer;
begin
  GetMem(P,Size);

      Writeln('Inside');
      Writeln('FastMem '+FormatFloat('#,', GetUsedMemoryFastMem));
      Writeln('Windows '+FormatFloat('#,', GetUsedMemoryWindows));
      Writeln('');

  FreeMem(P);
end;

begin
      Writeln('Before');
      Writeln('FastMem '+FormatFloat('#,', GetUsedMemoryFastMem));
      Writeln('Windows '+FormatFloat('#,', GetUsedMemoryWindows));
      Writeln('');

      Test;

      Writeln('After');
      Writeln('FastMem '+FormatFloat('#,', GetUsedMemoryFastMem));
      Writeln('Windows '+FormatFloat('#,', GetUsedMemoryWindows));
      Writeln('');
      Readln;
end.

результаты, возвращаемые приложением:

Before
FastMem 1.844
Windows 3.633.152

Inside
FastMem 1.050.612
Windows 3.637.248

After
FastMem 2.036
Windows 3.633.152

Я хочу знать, почему результаты использования памяти различаются в Before и After:

Ответы [ 3 ]

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

Любой менеджер памяти (включая FastMM) несет некоторые накладные расходы, иначе Delphi мог бы просто использовать управление памятью Windows.

Разница, которую вы наблюдаете, - это накладные расходы:

  • структур, которые FastMM использует для отслеживания использования памяти,
  • фрагментов памяти, которые FastMM еще не вернул к управлению памятью Windows, чтобы оптимизировать подобные распределения памяти в будущем.
2 голосов
/ 15 декабря 2010

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

0 голосов
/ 12 февраля 2013

Как работает getmem / malloc / free?

Распределитель кучи - Используется malloc ...

1) Внутренне выделяет большие куски (обычно от 64 КБ до 1 Мегабайта) памятиа затем подразделяет фрагменты вверх, чтобы получить 100-байтовые и 200-байтовые объекты и строки в программе.Когда вы освобождаете память, все, что происходит, - это место, из которого она была выделена во внутреннем буфере или порции, затем помечается как свободная.НИЧЕГО НАСТОЯЩЕГО НЕ ПРОИСХОДИТ!

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

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

Это довольно наивное описание системы кучи, но большинство куч работает аналогичным образом, но оптимизирует их гораздо больше.Но ваш вопрос заключается в том, почему память не падает, а ответ заключается в том, что на самом деле ничто не освобождается.Внутренние страницы памяти сохраняются для следующего вызова «new» или «malloc» и т. Д. ...

ИЗОБРАЖЕНИЕ ЭТОГО

ВНУТРЕННЯЯ КАРТА - ОДИН ОГРОМНЫЙ БЛОК 100 КБ

You call "malloc(1000)" or "getmem(1000)" to get a 1K block of memory.

Тогда все, что происходит, это то, что блок памяти объемом 1 КБ берется из блока памяти объемом 100 КБ, оставляя в этом блоке 99 КБ памяти.Если вы продолжаете вызывать malloc или getmem, то он будет просто делить больший блок до тех пор, пока ему не понадобится еще один больший блок.

Каждый маленький блок памяти, выделенный при вызове malloc или getmem, фактически получает около 16 или 24 дополнительныхбайты (в зависимости от распределителя) дополнительной памяти.Эта память является битами, которые распределитель использует, чтобы знать, что выделено, а также где оно выделено.

...