0

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.

urkainian
  • 13
  • 3
  • Can you show an MCVE and include the leak report. Also, that branch is so old now. The collection code is massively changed and improved on develop. – David Heffernan Jul 19 '23 at 11:26
  • Is it stable to use develop branch. I was waiting for official 2.0 release, but may be I must switch to develop branch and use it. – urkainian Jul 20 '23 at 06:48
  • I'm not sure why Stefan hasn't released off develop yet. I was involved with some of the development of the new collections and sorting code, but it was years ago now. I guess only Stefan could answer your question. – David Heffernan Jul 20 '23 at 08:28
  • This has nothing to do with Spring4d but with https://quality.embarcadero.com/browse/RSP-34818 – Stefan Glienke Jul 20 '23 at 11:08
  • Yes, after some test I found than this has nothing with Spring4D. – urkainian Jul 21 '23 at 08:07

0 Answers0