delphiindyindy10idhttp

Delphi TIdHTTPServer gradually increase memory


I have a server build with TIdHTTPServer on XE6 (with default Indy 10 installation and default option set on component) for file download:

procedure CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
    AResponseInfo.ContentStream := TFileStream.Create('C:\MyFile.Exe', fmOpenRead or fmShareDenyNone);
end;

after many months (6 months) and a lot of request (less or more 1'000'000), the server process increase private memory (on task manager) over 50 MB.

Is TIdHTTPServer leaking memory?

Update:

in a small test application with

initialization
  ReportMemoryLeaksOnShutdown := True;

no leak are trown

I have also tried to use FastMM dll and this is the report (My SO is in italian)

--------------------------------2015/11/2 14:52:38-------------------------

Leak di un blocco. La dimensione è: 20

Questo blocco è stato allocato dal thread 0x730, e lo stack trace (indirizzo restituito) in quel momento era: 40678A 4087AF 408ED6 640996 [IdThreadSafe][IdThreadSafe][IdThreadSafe..TIdThreadSafeObjectList][144] 6C996F [IdGlobalProtocols.pas][IdGlobalProtocols][IdGlobalProtocols.IdGlobalProtocols][4743] 6C9984 [IdGlobalProtocols.pas][IdGlobalProtocols][IdGlobalProtocols.IdGlobalProtocols][4744] 6C99D5 [IdThread.pas][IdThread][IdThread.IdThread][732] 409F80 409FEC 40F4B7 [SysInit.pas][SysInit][SysInit.@InitExe][1191] 6CA144 [WMain.pas][WMain][WMain.WMain][295] 75C6337A [BaseThreadInitThunk] 77AF9882 [Unknown function at RtlInitializeExceptionChain] 77AF9855 [Unknown function at RtlInitializeExceptionChain]

Il blocco è attualmente usato da una istanza della classe: TIdThreadSafeInteger

Il numero di allocazione è: 475

Dump della memoria di 256 byte partendo dall'indirizzo del puntatore 7EF3D2C0: FC 02 64 00 60 0F FA 7E 00 00 00 00 00 00 00 00 0B 12 7A 17 80 80 80 80 00 00 00 00 B1 D5 F3 7E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E2 01 00 00 8A 67 40 00 AF 87 40 00 D6 8E 40 00 A4 88 40 00 8D 85 D2 00 BA 85 D2 00 15 FC 4C 00 9E FB 4C 00 05 43 4B 00 ED 91 66 00 5D 9A 6C 00 80 9F 40 00 EC 9F 40 00 B7 F4 40 00 44 A1 6C 00 7A 33 C6 75 82 98 AF 77 55 98 AF 77 00 00 00 00 00 00 00 00 00 00 00 00 30 07 00 00 30 07 00 00 A6 67 40 00 CD 87 40 00 21 8F 40 00 C6 88 40 00 D3 88 40 00 38 FD 4C 00 D3 88 40 00 62 43 4B 00 D3 88 40 00 3E 92 66 00 14 9F 40 00 14 A3 40 00 87 A1 6C 00 7A 33 C6 75 82 98 AF 77 55 98 AF 77 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 BC 69 4E 00 45 BC CB 52 A0 41 D3 00 80 80 80 80 BA 43 34 AD 80 80 80 80 ü . d . ` . ú ~ . . . . . . . . . . z . € € € € . . . . ± Õ ó ~ . . . . . . . . . . . . . . . . â . . . Š g @ . ¯ ‡ @ . Ö Ž @ . ¤ ˆ @ . … Ò . º … Ò . . ü L . ž û L . . C K . í ‘ f . ] š l . € Ÿ @ . ì Ÿ @ . · ô @ . D ¡ l . z 3 Æ u ‚ ˜ ¯ w U ˜ ¯ w . . . . . . . . . . . . 0 . . . 0 . . . ¦ g @ . Í ‡ @ . ! @ . Æ ˆ @ . Ó ˆ @ . 8 ý L . Ó ˆ @ . b C K . Ó ˆ @ . > ’ f . . Ÿ @ . . £ @ . ‡ ¡ l . z 3 Æ u ‚ ˜ ¯ w U ˜ ¯ w . . . . . . . . . . . . . . . . . . . . . . . . ¼ i N . E ¼ Ë R   A Ó . € € € € º C 4 ­ € € € €

--------------------------------2015/11/2 14:52:38------------------------- Leak di un blocco. La dimensione è: 36

Questo blocco è stato allocato dal thread 0x730, e lo stack trace (indirizzo restituito) in quel momento era: 40678A 4087AF 408ED6 440106 [System.SyncObjs.pas][System][System.SyncObjs.TEvent.Create][827] 412FEA [Winapi.Windows.pas][Winapi][Winapi.Windows.GetProcAddress][34295] 6C98AB [IdStack.pas][IdStack][IdStack.IdStack][1138] 409F80 409FEC 40F4B7 [SysInit.pas][SysInit][SysInit.@InitExe][1191] 6CA144 [WMain.pas][WMain][WMain.WMain][295] 75C6337A [BaseThreadInitThunk] 77AF9882 [Unknown function at RtlInitializeExceptionChain] 77AF9855 [Unknown function at RtlInitializeExceptionChain]

Il blocco è attualmente usato da una istanza della classe: TIdCriticalSection

Il numero di allocazione è: 458

Dump della memoria di 256 byte partendo dall'indirizzo del puntatore 7EFA0A60: 90 D7 60 00 C0 9B 8A 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 CC A7 B0 80 80 80 80 00 00 00 00 91 0B FA 7E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 D1 01 00 00 8A 67 40 00 A3 A4 40 00 D4 A6 40 00 D1 E3 40 00 0E B4 AF 77 B5 33 AF 77 E3 2F AF 77 FA FA AD 77 2B D7 C6 75 48 D7 C6 75 BA D6 C6 75 7E D6 C6 75 91 D6 C6 75 32 FA AD 77 1A D6 C6 75 04 D4 C6 75 FE D5 C6 75 34 47 B1 77 A1 47 B1 77 09 F2 AE 77 74 F2 AE 77 30 07 00 00 30 07 00 00 A6 67 40 00 5D A5 40 00 41 A1 40 00 4B B4 62 00 14 9F 40 00 14 A3 40 00 87 A1 6C 00 7A 33 C6 75 82 98 AF 77 55 98 AF 77 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 22 00 00 00 B0 04 02 00 70 93 97 CA × ` . À › Š . ÿ ÿ ÿ ÿ . . . . . . . . . . . . . . . . . . . . . Ì § ° € € € € . . . . ‘ . ú ~ . . . . . . . . . . . . . . . . Ñ . . . Š g @ . £ ¤ @ . Ô ¦ @ . Ñ ã @ . . ´ ¯ w µ 3 ¯ w ã / ¯ w ú ú ­ w + × Æ u H × Æ u º Ö Æ u ~ Ö Æ u ‘ Ö Æ u 2 ú ­ w . Ö Æ u . Ô Æ u þ Õ Æ u 4 G ± w ¡ G ± w . ò ® w t ò ® w 0 . . . 0 . . . ¦ g @ . ] ¥ @ . A ¡ @ . K ´ b . . Ÿ @ . . £ @ . ‡ ¡ l . z 3 Æ u ‚ ˜ ¯ w U ˜ ¯ w . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " . . . ° . . . p “ — Ê

--------------------------------2015/11/2 14:52:38------------------------- Leak di un blocco. La dimensione è: 36

Questo blocco è stato allocato dal thread 0x730, e lo stack trace (indirizzo restituito) in quel momento era: 40678A 4087AF 408ED6 440106 [System.SyncObjs.pas][System][System.SyncObjs.TEvent.Create][827] 4087B8 6409AF [IdThreadSafe][IdThreadSafe][IdThreadSafe..TIdThreadSafeObjectList][144] 6C99D5 [IdThread.pas][IdThread][IdThread.IdThread][732] 409F80 409FEC 40F4B7 [SysInit.pas][SysInit][SysInit.@InitExe][1191] 6CA144 [WMain.pas][WMain][WMain.WMain][295] 75C6337A [BaseThreadInitThunk] 77AF9882 [Unknown function at RtlInitializeExceptionChain] 77AF9855 [Unknown function at RtlInitializeExceptionChain]

Il blocco è attualmente usato da una istanza della classe: TIdCriticalSection

Il numero di allocazione è: 476

Dump della memoria di 256 byte partendo dall'indirizzo del puntatore 7EFA0F60: 90 D7 60 00 E8 9B 8A 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 76 7F C8 17 80 80 80 80 00 00 00 00 91 10 FA 7E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 DF 01 00 00 8A 67 40 00 A3 A4 40 00 30 A9 40 00 26 6D 4B 00 81 68 4B 00 12 3B 66 00 2D 9A 6C 00 80 9F 40 00 EC 9F 40 00 B7 F4 40 00 44 A1 6C 00 7A 33 C6 75 82 98 AF 77 55 98 AF 77 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 07 00 00 30 07 00 00 5D A5 40 00 95 BA 40 00 DD B9 40 00 DD BA 40 00 45 C8 40 00 E9 C4 40 00 25 C5 40 00 FA C6 40 00 9B 6E 4B 00 B6 67 4B 00 D3 88 40 00 7A 40 66 00 14 9F 40 00 14 A3 40 00 87 A1 6C 00 7A 33 C6 75 82 98 AF 77 55 98 AF 77 00 00 00 00 00 00 00 00 00 00 00 00 18 00 00 00 B0 04 02 00 29 94 D2 50 × ` . è › Š . ÿ ÿ ÿ ÿ . . . . . . . . . . . . . . . . . . . . v È . € € € € . . . . ‘ . ú ~ . . . . . . . . . . . . . . . . ß . . . Š g @ . £ ¤ @ . 0 © @ . & m K . h K . . ; f . - š l . € Ÿ @ . ì Ÿ @ . · ô @ . D ¡ l . z 3 Æ u ‚ ˜ ¯ w U ˜ ¯ w . . . . . . . . . . . . . . . . . . . . . . . . . . . . 0 . . . 0 . . . ] ¥ @ . • º @ . Ý ¹ @ . Ý º @ . E È @ . é Ä @ . % Å @ . ú Æ @ . › n K . ¶ g K . Ó ˆ @ . z @ f . . Ÿ @ . . £ @ . ‡ ¡ l . z 3 Æ u ‚ ˜ ¯ w U ˜ ¯ w . . . . . . . . . . . . . . . . ° . . . ) ” Ò P


Solution

  • It's not abnormal for long-running processes to have a memory footprint after some running-time that is larger than the memory footprint from shortly after start-up. Even when the process is temporarily not processing requests. Since memory allocations take some time, some memory managers (and I think FastMM does this as well) will keep memory that is not longer in use still allocated, ready for when the software needs to assign new objects or variables, so the memory can be re-used.

    In your case, if possible, let the process run another few months and see wether the memory usage is stable and no longer keeps growing. If it's important this memory should be made available again for other processes, check if you can tweak FastMM with options or configuration settings.