7
votes

I've a weird problem with my application, its memory usage goes up a few hundred megabytes at once every now and then and eventually the application freezes. The application is written with Delphi, it uses database, COM (for OPC) and TCP/IP.

With FastMM I've got following the screen shot of memory usage. I'm not completely sure how to read that table, but it looks like something has allocated 296463552 bytes (0x100fb000, is that "magic number"?) three times.

memory usage

Any ideas? Is there any way to track non-Delphi-MM memory allocations?

I'm using Delphi 2007 with FastMM 4.96.

Edit:

I wrote a small helper class using IMallocSpy to track COM memory allocations. Here's excerpt from what I got:

00119023    5:52:27.484 [4496] TCOMAllocSpy.PreRealloc size: 269462304
00119024    5:52:27.734 [4496] (0002760C){ntdll.dll   } [7C82860C] KiFastSystemCallRet + $0 
00119025    5:52:27.734 [4496] (0009F83A){MyApp.exe} [004A083A] JclDebug.JclCreateThreadStackTrace (Line 3943, "JclDebug.pas" + 7) + $1E 
00119026    5:52:27.734 [4496] (003D496A){MyApp.exe} [007D596A] ComLeakHelper.TCOMAllocSpy.DebugStack (Line 46, "ComLeakHelper.pas" + 2) + $9 
00119027    5:52:27.734 [4496] (003D4B52){MyApp.exe} [007D5B52] ComLeakHelper.TCOMAllocSpy.PreRealloc (Line 125, "ComLeakHelper.pas" + 4) + $2 
00119028    5:52:27.734 [4496] (000053B6){MyApp.exe} [004063B6] System.@WStrAsg (Line 14090, "sys\system.pas" + 10) + $0 
00119029    5:52:27.734 [4496] (002E4490){MyApp.exe} [006E5490] DBXCommon.TDBXCommand.SetText (Line 5304, "..\..\..\..\..\src\pas\dbx\driver\DBXCommon.pas" + 13) + $5 
00119030    5:52:27.734 [4496] (0010A340){MyApp.exe} [0050B340] WideStrings.TWideStrings.GetValue (Line 580, "common\WideStrings.pas" + 3) + $D 
00119031    5:52:27.734 [4496] (002E1AFC){MyApp.exe} [006E2AFC] DBXCommon.TDBXProperties.GetValue (Line 4046, "..\..\..\..\..\src\pas\dbx\driver\DBXCommon.pas" + 1) + $7 
00119032    5:52:27.734 [4496] (002E3FC9){MyApp.exe} [006E4FC9] DBXCommon.TDBXConnectionEx.GetProductName (Line 5071, "..\..\..\..\..\src\pas\dbx\driver\DBXCommon.pas" + 1) + $E 
00119033    5:52:27.734 [4496] (003765FA){MyApp.exe} [007775FA] SqlExpr.TSQLConnection.DoConnect (Line 2467, "..\..\..\..\..\src\pas\dbx\vcl\SqlExpr.pas" + 66) + $21 
00119034    5:52:27.734 [4496] (0011876D){MyApp.exe} [0051976D] DB.TCustomConnection.SetConnected (Line 2628, "DB.pas" + 8) + $4 
00119035    5:52:27.734 [4496] (00118728){MyApp.exe} [00519728] DB.TCustomConnection.Open (Line 2611, "DB.pas" + 0) + $4 
00119036    5:52:27.734 [4496] (00375D6F){MyApp.exe} [00776D6F] SqlExpr.TSQLConnection.CheckConnection (Line 2302, "..\..\..\..\..\src\pas\dbx\vcl\SqlExpr.pas" + 4) + $2 
00119037    5:52:27.734 [4496] (00379241){MyApp.exe} [0077A241] SqlExpr.TCustomSQLDataSet.CheckConnection (Line 3955, "..\..\..\..\..\src\pas\dbx\vcl\SqlExpr.pas" + 2) + $2 
00119038    5:52:27.734 [4496] (0037968A){MyApp.exe} [0077A68A] SqlExpr.TCustomSQLDataSet.OpenCursor (Line 4045, "..\..\..\..\..\src\pas\dbx\vcl\SqlExpr.pas" + 3) + $4 
00119039    5:52:27.734 [4496] (00125EA9){MyApp.exe} [00526EA9] DB.TDataSet.SetActive (Line 9245, "DB.pas" + 12) + $7 
00119040    5:52:27.734 [4496] (00125CA1){MyApp.exe} [00526CA1] DB.TDataSet.Open (Line 9201, "DB.pas" + 1) + $6 
...

So, the problem seems to be in database connection. I'm using Firebird 2.1, DBExpress and InterXpress for Firebird drivers from Upscene.

Edit2: This seems to analyze similar problem, at least the focus is on same lines as here: http://www.yac.com.pl/mt.texts.sqlexpr-2.en.html

3
You could try if VMMap from sysinternals gives you more information but one sure way to track this would be to use procdump (from sysinternals). Have it automatically create a dump file when a memory limit gets exceeded and analyze the dump with WinDbg.Lieven Keersmaekers
VMMap gave basically same information, there's one (or more) big block allocated. It doesn't help to find out the source of the leakHarriv
FastMM 4.90 has a AllocateLargeBlockfunction. I would try placing a conditional breakpoint here on a large enough size.Lieven Keersmaekers
Those blocks are "System Allocated", which can be created at least with CoTaskMemAlloc function (maybe others too?) from ole32.dll. According to my tests FastMM is bypassed completely when CoTaskMem* functions are called.Harriv
<long shot>Have you tried using the memory profiler from AQTime? If I recall correct, it allows you to trace all memory allocations (but tracing it will slow your application down to a crawl). </long shot>Lieven Keersmaekers

3 Answers

2
votes

The problem is bug in Delphi 2007 DbExpress which surface in multithreaded environment (It's not thread safe, after all). More information here: http://www.yac.com.pl/mt.texts.sqlexpr-2.en.html

1
votes

When your application is frozen, your can try to look at the stack to discover why it is frozen: http://code.google.com/p/asmprofiler/wiki/ProcessStackViewer

You can try memproof to trace all resource allocation (and their stacktrace): http://www.torry.net/tools/debug/memory/memp0948.zip

0
votes

Try EurekaLog to locate the problem.