Does anyone else have a problem with memory leaks when using Spring4D framework and IMultiMap<TKye, TValue>
collections?
I use the last released version from the master branch (1.2.6), and when I use the ForEach(Action<T>)
method, it generates a memory leak.
My collection is IMultiMap<Integer, string>
. Here is an example:
for var Id in AMultiMap.Keys do
begin
var sComposeValues := string.Empty;
AMultiMap.Items[Id].ForEach(
procedure(const AValue: string)
begin
if (sComposeValues.IsEmpty) then
begin
sComposeValues := string.Format('(%s)', [AValue]);
end
else
begin
sComposeValues := string.Format('%s and (%s)', [sComposeValues, AValue]);
end;
end
);
DoSomethin(sComposeValues);
end;
If I use a for..in
loop, there is no memory leak:
for var Id in AMultiMap.Keys do
begin
var sComposeValues := string.Empty;
for var sValue in AMultiMap.Items[Id] do
begin
if (sComposeValues.IsEmpty) then
begin
sComposeValues := string.Format('(%s)', [sValue]);
end
else
begin
sComposeValues := string.Format('%s and (%s)', [sComposeValues, sValue]);
end;
end;
DoSomethin(sComposeValues);
end;
Edit:
I make some changes to code and now there is no memory leak. It's all about where I define inline variable sComposeValues
. Here is my quick MCVE:
type
TForm1 = class(TForm)
btn1: TBitBtn;
mmo: TMemo;
procedure btnClick(Sender: TObject);
private
procedure InitMultiMap(const AMultiMap: IMultiMap<System.Integer, string>);
procedure FillByForEach(const AMultiMap: IMultiMap<System.Integer, string>; const AList: TStrings);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TForm1 }
procedure TForm1.btnClick(Sender: TObject);
begin
var mmList := TCollections.CreateMultiMap<System.Integer, string>();
Self.InitMultiMap(mmList);
Self.FillByForEach(mmList, mmo.Lines);
end;
procedure TForm1.FillByForEach(const AMultiMap: IMultiMap<System.Integer, string>; const AList: TStrings);
begin
AList.Clear();
var sComposeValues: string; /// define inline before loop iteration - NO memory leak
for var Id in AMultiMap.Keys do
begin
//var sComposeValues := string.Empty; ///define inline variable in for every iteration - HAS memory leak
sComposeValues := string.Empty; // skip line if inline variable is define within loop
AMultiMap.Items[Id].ForEach(
procedure(const AValue: string)
begin
if (sComposeValues.IsEmpty) then
begin
sComposeValues := string.Format('(%s)', [AValue]);
end
else
begin
sComposeValues := string.Format('%s and (%s)', [sComposeValues, AValue]);
end;
end
);
AList.Add(sComposeValues);
end;
end;
procedure TForm1.InitMultiMap(const AMultiMap: IMultiMap<System.Integer, string>);
begin
AMultiMap.Clear();
for var i := 1 to 5 do
begin
for var j := 1 to 5 do
begin
AMultiMap.Add(i, string.Format('ValueId_%d=%d', [i,j+10]));
end;
end;
end;
end.
There is five(5) iterations and it's left 4 X UnicodeString
blocks. It frees memory only from last iteration from TKye. Here is leak report:
--------------------------------2023/7/20 9:42:45--------------------------------
A memory block has been leaked. The size is: 212
This block was allocated by thread 0x4D5C, and the stack trace (return addresses) at the time was:
257212 [System.pas][System][@GetMem$qqri][4949]
25A5D3 [System.pas][System][@NewUnicodeString$qqri][26005]
25A814 [System.pas][System][@UStrFromPWCharLen$qqrr20System.UnicodeStringpbi][26617]
27AE10 [System.SysUtils.pas][System.SysUtils][Sysutils.FmtStr$qqrr20System.UnicodeStringx20System.UnicodeStringpx14System.TVarRecxirx31System.Sysutils.TFormatSettings][13001]
74B0B9B8 [Unknown function at LoadCursorW]
F32D29D
774416FC [ZwAllocateVirtualMemory]
F32D2A4
F30D7E9
F307201
F307212
The block is currently used for an object of class: UnicodeString
The allocation number is: 1295
Current memory dump of 256 bytes starting at pointer address 7FC20DC0:
B0 04 02 00 01 00 00 00 5A 00 00 00 28 00 56 00 61 00 6C 00 75 00 65 00 49 00 64 00 5F 00 32 00
3D 00 31 00 31 00 29 00 20 00 61 00 6E 00 64 00 20 00 28 00 56 00 61 00 6C 00 75 00 65 00 49 00
64 00 5F 00 32 00 3D 00 31 00 32 00 29 00 20 00 61 00 6E 00 64 00 20 00 28 00 56 00 61 00 6C 00
75 00 65 00 49 00 64 00 5F 00 32 00 3D 00 31 00 33 00 29 00 20 00 61 00 6E 00 64 00 20 00 28 00
56 00 61 00 6C 00 75 00 65 00 49 00 64 00 5F 00 32 00 3D 00 31 00 34 00 29 00 20 00 61 00 6E 00
64 00 20 00 28 00 56 00 61 00 6C 00 75 00 65 00 49 00 64 00 5F 00 32 00 3D 00 31 00 35 00 29 00
00 00 74 70 92 47 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 00 00 00 00 60 0A C2 7F
00 00 00 00 00 00 00 00 24 8F 26 00 00 00 00 00 16 05 00 00 12 72 25 00 D3 A5 25 00 14 A8 25 00
° . . . . . . . Z . . . ( . V . a . l . u . e . I . d . _ . 2 .
= . 1 . 1 . ) . . a . n . d . . ( . V . a . l . u . e . I .
d . _ . 2 . = . 1 . 2 . ) . . a . n . d . . ( . V . a . l .
u . e . I . d . _ . 2 . = . 1 . 3 . ) . . a . n . d . . ( .
V . a . l . u . e . I . d . _ . 2 . = . 1 . 4 . ) . . a . n .
d . . ( . V . a . l . u . e . I . d . _ . 2 . = . 1 . 5 . ) .
. . t p ’ G Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ . . . . ` . В
. . . . . . . . $ Џ & . . . . . . . . . . r % . У Ґ % . . Ё % .
--------------------------------2023/7/20 9:42:45--------------------------------
A memory block has been leaked. The size is: 212
This block was allocated by thread 0x4D5C, and the stack trace (return addresses) at the time was:
257212 [System.pas][System][@GetMem$qqri][4949]
25A5D3 [System.pas][System][@NewUnicodeString$qqri][26005]
25A814 [System.pas][System][@UStrFromPWCharLen$qqrr20System.UnicodeStringpbi][26617]
27AE10 [System.SysUtils.pas][System.SysUtils][Sysutils.FmtStr$qqrr20System.UnicodeStringx20System.UnicodeStringpx14System.TVarRecxirx31System.Sysutils.TFormatSettings][13001]
74B0B9B8 [Unknown function at LoadCursorW]
F32D29D
774416FC [ZwAllocateVirtualMemory]
F32D2A4
F30D7E9
F307201
F307212
The block is currently used for an object of class: UnicodeString
The allocation number is: 1302
Current memory dump of 256 bytes starting at pointer address 7FC20F20:
B0 04 02 00 01 00 00 00 5A 00 00 00 28 00 56 00 61 00 6C 00 75 00 65 00 49 00 64 00 5F 00 35 00
3D 00 31 00 31 00 29 00 20 00 61 00 6E 00 64 00 20 00 28 00 56 00 61 00 6C 00 75 00 65 00 49 00
64 00 5F 00 35 00 3D 00 31 00 32 00 29 00 20 00 61 00 6E 00 64 00 20 00 28 00 56 00 61 00 6C 00
75 00 65 00 49 00 64 00 5F 00 35 00 3D 00 31 00 33 00 29 00 20 00 61 00 6E 00 64 00 20 00 28 00
56 00 61 00 6C 00 75 00 65 00 49 00 64 00 5F 00 35 00 3D 00 31 00 34 00 29 00 20 00 61 00 6E 00
64 00 20 00 28 00 56 00 61 00 6C 00 75 00 65 00 49 00 64 00 5F 00 35 00 3D 00 31 00 35 00 29 00
00 00 70 37 24 45 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 00 00 00 00 60 0A C2 7F
00 00 00 00 00 00 00 00 24 8F 26 00 00 00 00 00 1D 05 00 00 12 72 25 00 D3 A5 25 00 14 A8 25 00
° . . . . . . . Z . . . ( . V . a . l . u . e . I . d . _ . 5 .
= . 1 . 1 . ) . . a . n . d . . ( . V . a . l . u . e . I .
d . _ . 5 . = . 1 . 2 . ) . . a . n . d . . ( . V . a . l .
u . e . I . d . _ . 5 . = . 1 . 3 . ) . . a . n . d . . ( .
V . a . l . u . e . I . d . _ . 5 . = . 1 . 4 . ) . . a . n .
d . . ( . V . a . l . u . e . I . d . _ . 5 . = . 1 . 5 . ) .
. . p 7 $ E Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ . . . . ` . В
. . . . . . . . $ Џ & . . . . . . . . . . r % . У Ґ % . . Ё % .
--------------------------------2023/7/20 9:42:45--------------------------------
A memory block has been leaked. The size is: 212
This block was allocated by thread 0x4D5C, and the stack trace (return addresses) at the time was:
257212 [System.pas][System][@GetMem$qqri][4949]
25A5D3 [System.pas][System][@NewUnicodeString$qqri][26005]
25A814 [System.pas][System][@UStrFromPWCharLen$qqrr20System.UnicodeStringpbi][26617]
27AE10 [System.SysUtils.pas][System.SysUtils][Sysutils.FmtStr$qqrr20System.UnicodeStringx20System.UnicodeStringpx14System.TVarRecxirx31System.Sysutils.TFormatSettings][13001]
74B0B9B8 [Unknown function at LoadCursorW]
F32D29D
774416FC [ZwAllocateVirtualMemory]
F32D2A4
F30D7E9
F307201
F307212
The block is currently used for an object of class: UnicodeString
The allocation number is: 1309
Current memory dump of 256 bytes starting at pointer address 7FC21080:
B0 04 02 00 01 00 00 00 5A 00 00 00 28 00 56 00 61 00 6C 00 75 00 65 00 49 00 64 00 5F 00 34 00
3D 00 31 00 31 00 29 00 20 00 61 00 6E 00 64 00 20 00 28 00 56 00 61 00 6C 00 75 00 65 00 49 00
64 00 5F 00 34 00 3D 00 31 00 32 00 29 00 20 00 61 00 6E 00 64 00 20 00 28 00 56 00 61 00 6C 00
75 00 65 00 49 00 64 00 5F 00 34 00 3D 00 31 00 33 00 29 00 20 00 61 00 6E 00 64 00 20 00 28 00
56 00 61 00 6C 00 75 00 65 00 49 00 64 00 5F 00 34 00 3D 00 31 00 34 00 29 00 20 00 61 00 6E 00
64 00 20 00 28 00 56 00 61 00 6C 00 75 00 65 00 49 00 64 00 5F 00 34 00 3D 00 31 00 35 00 29 00
00 00 09 36 24 45 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 00 00 00 00 60 0A C2 7F
00 00 00 00 00 00 00 00 24 8F 26 00 00 00 00 00 24 05 00 00 12 72 25 00 D3 A5 25 00 14 A8 25 00
° . . . . . . . Z . . . ( . V . a . l . u . e . I . d . _ . 4 .
= . 1 . 1 . ) . . a . n . d . . ( . V . a . l . u . e . I .
d . _ . 4 . = . 1 . 2 . ) . . a . n . d . . ( . V . a . l .
u . e . I . d . _ . 4 . = . 1 . 3 . ) . . a . n . d . . ( .
V . a . l . u . e . I . d . _ . 4 . = . 1 . 4 . ) . . a . n .
d . . ( . V . a . l . u . e . I . d . _ . 4 . = . 1 . 5 . ) .
. . . 6 $ E Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ . . . . ` . В
. . . . . . . . $ Џ & . . . . . $ . . . . r % . У Ґ % . . Ё % .
--------------------------------2023/7/20 9:42:45--------------------------------
A memory block has been leaked. The size is: 212
This block was allocated by thread 0x4D5C, and the stack trace (return addresses) at the time was:
257212 [System.pas][System][@GetMem$qqri][4949]
25A5D3 [System.pas][System][@NewUnicodeString$qqri][26005]
25A814 [System.pas][System][@UStrFromPWCharLen$qqrr20System.UnicodeStringpbi][26617]
27AE10 [System.SysUtils.pas][System.SysUtils][Sysutils.FmtStr$qqrr20System.UnicodeStringx20System.UnicodeStringpx14System.TVarRecxirx31System.Sysutils.TFormatSettings][13001]
74B0B9B8 [Unknown function at LoadCursorW]
F32D29D
774416FC [ZwAllocateVirtualMemory]
F32D2A4
F30D7E9
F307201
F307212
The block is currently used for an object of class: UnicodeString
The allocation number is: 1316
Current memory dump of 256 bytes starting at pointer address 7FC211E0:
B0 04 02 00 01 00 00 00 5A 00 00 00 28 00 56 00 61 00 6C 00 75 00 65 00 49 00 64 00 5F 00 31 00
3D 00 31 00 31 00 29 00 20 00 61 00 6E 00 64 00 20 00 28 00 56 00 61 00 6C 00 75 00 65 00 49 00
64 00 5F 00 31 00 3D 00 31 00 32 00 29 00 20 00 61 00 6E 00 64 00 20 00 28 00 56 00 61 00 6C 00
75 00 65 00 49 00 64 00 5F 00 31 00 3D 00 31 00 33 00 29 00 20 00 61 00 6E 00 64 00 20 00 28 00
56 00 61 00 6C 00 75 00 65 00 49 00 64 00 5F 00 31 00 3D 00 31 00 34 00 29 00 20 00 61 00 6E 00
64 00 20 00 28 00 56 00 61 00 6C 00 75 00 65 00 49 00 64 00 5F 00 31 00 3D 00 31 00 35 00 29 00
00 00 A2 34 24 45 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 00 00 00 00 21 14 C2 7F
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2B 05 00 00 12 72 25 00 D3 A5 25 00 14 A8 25 00
° . . . . . . . Z . . . ( . V . a . l . u . e . I . d . _ . 1 .
= . 1 . 1 . ) . . a . n . d . . ( . V . a . l . u . e . I .
d . _ . 1 . = . 1 . 2 . ) . . a . n . d . . ( . V . a . l .
u . e . I . d . _ . 1 . = . 1 . 3 . ) . . a . n . d . . ( .
V . a . l . u . e . I . d . _ . 1 . = . 1 . 4 . ) . . a . n .
d . . ( . V . a . l . u . e . I . d . _ . 1 . = . 1 . 5 . ) .
. . ў 4 $ E Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ Ђ . . . . ! . В
. . . . . . . . . . . . . . . . + . . . . r % . У Ґ % . . Ё % .
--------------------------------2023/7/20 9:42:45--------------------------------
This application has leaked memory. The small block leaks are (excluding expected leaks registered by pointer):
181 - 212 bytes: UnicodeString x 4
Note: Memory leak detail is logged to a text file in the same folder as this application. To disable this memory leak check, undefine "EnableMemoryLeakReporting".
After update to develop
branch and rebuild Spring4D framework there is still memory leak when use inline variable sComposeValues
in .Keys
iterations. It still allocate memory for variable for every scope, but did no free on the end of scope, this happens only for last scope.