Зачем использовать 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.