- Код: Выделить всё
{$MODE OBJFPC}
type
TObj = object
S: AnsiString;
constructor Init(const Value: AnsiString);
destructor Done; virtual;
end;
constructor TObj.Init(const Value: AnsiString);
begin
S := Value;
end;
destructor TObj.Done;
begin
end;
var
P: Pointer;
begin
P := GetMem(SizeOf(TObj));
TObj(P^).Init(ParamStr(0) + ' (modification)'); // <- созданная тут строка утечёт
TObj(P^).Done;
FreeMem(P);
end.
На первый взгляд с кодом всё в порядке: память из-под объекта мы в конце удаляем, а для создания и уничтожения используем честные конструктор и деструктор. Но в коде есть упомянутая утечка памяти:
- Код: Выделить всё
D:\data\temp>fpc -gh -gl m.pas && m.exe
Free Pascal Compiler version 3.0.4 [2017/10/06] for i386
Copyright (c) 1993-2017 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling m.pas
Linking m.exe
26 lines compiled, 0.1 sec, 46704 bytes code, 1908 bytes data
Heap dump by heaptrc unit
3 memory blocks allocated : 85/88
2 memory blocks freed : 39/40
1 unfreed memory blocks : 46
True heap size : 163840 (80 used in System startup)
True free heap : 163632
Should be : 163648
Call trace for block $034B15C0 size 46
$004015AA main, line 23 of m.pas
Как я понимаю данную проблему: деструктор считается обычной процедурой (легаси от Turbo Pascal), поэтому он не приводит к освобождению строки и она утекает.
В данном конкретном случае проблема решается заменой GetMem и FreeMem на New и Dispose. Но представим себе несколько других ситуаций, когда New не поможет:
1. Я хочу выделить память сразу под 100 объектов одним вызовом GetMem
2. Я размещаю объекты в некотором пуле, какие именно - станет известно в рантайме
Как мне правильно уничтожать объекты в подобных ситуациях? Может есть какой-нибудь MODESWITCH, который делает так, что деструктор освобождает все управляемые поля в объекте?