Зачем использовать FreeMem/Dispose для освобождения памяти, но нет памяти?

Я использую AllocMem/GetMem/New подпрограммы для выделения памяти, а затем использую программы FreeMem/Dispose для освобождения памяти. Но я обнаружил (через Process Explorer), что размер памяти процесса не уменьшается.

Если я использую API GlobalAllocPtr/HeapAlloc и GlobalFreePtr/HeapFree, размер памяти уменьшится.

Вот мой тестовый код:

type
  TMyRec = record
    Name: string;
    TickCount: Cardinal;
    Buf: array[0..1024 - 1] of byte;
  end;
  PMyRec = ^TMyRec;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FList.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FList := TList.Create;
  ReportMemoryLeaksOnShutdown := true;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
  Size: Integer;
  Rec: PMyRec;
  Heap: Cardinal;
begin
  Size := SizeOf(TMyRec);
  Heap := GetProcessHeap;
  for I := 0 to 2000 - 1 do
  begin
    Rec := AllocMem(Size);                              // Delphi routine
    //GetMem(Rec, Size);                                // Delphi routine
    //New(Rec);                                         // Delphi routine

    //Rec := GlobalAllocPtr(GPTR, Size);                // Windows API
    //Rec := HeapAlloc(Heap, HEAP_ZERO_MEMORY, Size);   // Windows API
    FList.Add(Rec);
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  i: Integer;
  Size: Integer;
  Rec: PMyRec;
  Heap: Cardinal;
begin
  Size := SizeOf(TMyRec);
  Heap := GetProcessHeap;
  for i := FList.Count - 1 downto 0 do
  begin
    Rec := PMyRec(FList.Items[i]);
    FreeMem(Rec, Size);            // Delphi routine
    //Dispose(Rec);                // Delphi routine

    //GlobalFreePtr(Rec);          // Windows API
    //HeapFree(Heap, 0, Rec);      // Windows API
  end;
  FList.Clear;
end;

Ответ 1

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

BTW никогда не использует FreeMem для записей с управляемыми потоками времени (например, строки, как в вашем примере) - это приводит к утечкам памяти. Вместо этого используйте Dispose.

Также никогда не используйте GetMem для записей с управляемыми потоками времени жизни (строка комментария в вашем примере) - это приводит к нарушениям доступа. Используйте New.

Ответ 2

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

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

Ответ 3

Менеджер памяти Delphi фактически выделяет/освобождает память по страницам.

Ответ 4

Вы не должны указывать функцию Size to FreeMem. Требуется только один параметр - указатель. В противном случае ваш код выглядит просто отлично. Мне просто интересно - почему вы используете malloc и бесплатно вместо new и delete/dispose? Или GetMem и FreeMem.