Утечка памяти с помощью Delphi / DBExpress

У меня странная проблема с моим приложением, его использование памяти время от времени увеличивается на несколько сотен мегабайт, и в конечном итоге приложение зависает. Приложение написано на Delphi, использует базу данных, COM (для OPC) и TCP / IP.

С FastMM я сделал снимок экрана с использованием памяти. Я не совсем уверен, как читать эту таблицу, но похоже, что что-то выделило 296463552 байта (0x100fb000, это «магическое число»?) Три раза.

использование памяти

Любые идеи? Есть ли способ отслеживать выделение памяти, отличной от Delphi-MM?

Я использую Delphi 2007 с FastMM 4.96.

Изменить:

Я написал небольшой вспомогательный класс с использованием IMallocSpy для отслеживания распределения памяти COM. Вот отрывок из того, что у меня получилось:

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 
...

Итак, проблема, похоже, связана с подключением к базе данных. Я использую Firebird 2.1, DBExpress и InterXpress для драйверов Firebird от Upscene.

Edit2: Это похоже на анализ аналогичной проблемы, по крайней мере, основное внимание уделяется тем же строкам, что и здесь: http://www.yac.com.pl/mt.texts.sqlexpr-2.en.html


person Harriv    schedule 28.09.2010    source источник
comment
Вы можете попробовать, если VMMap от sysinternals предоставит вам больше информации, но один верный способ отследить это - использовать procdump (от sysinternals). Пусть он автоматически создает файл дампа при превышении лимита памяти и анализирует дамп с помощью WinDbg.   -  person Lieven Keersmaekers    schedule 29.09.2010
comment
VMMap предоставил в основном ту же информацию, выделен один (или несколько) больших блоков. Не помогает выяснить источник утечки   -  person Harriv    schedule 29.09.2010
comment
FastMM 4.90 имеет функцию AllocateLargeBlock. Я бы попробовал разместить здесь условную точку останова на достаточно большом размере.   -  person Lieven Keersmaekers    schedule 29.09.2010
comment
Эти блоки выделены системой, и их можно создать, по крайней мере, с помощью функции CoTaskMemAlloc (может быть, и других?) Из ole32.dll. Согласно моим тестам, FastMM полностью игнорируется при вызове функций CoTaskMem *.   -  person Harriv    schedule 29.09.2010
comment
‹Длинный план› Вы пробовали использовать профилировщик памяти от AQTime? Если я правильно помню, он позволяет вам отслеживать все распределения памяти (но отслеживание замедлит ваше приложение до обхода). ‹/ Дальний план›   -  person Lieven Keersmaekers    schedule 30.09.2010


Ответы (3)


Проблема заключается в ошибке в Delphi 2007 DbExpress, которая появляется в многопоточной среде (в конце концов, это небезопасно для потоков). Дополнительная информация здесь: http://www.yac.com.pl/mt.texts.sqlexpr-2.en.html

person Harriv    schedule 01.10.2010

Когда ваше приложение заморожено, вы можете попытаться посмотреть на стек, чтобы выяснить, почему оно заморожено: http://code.google.com/p/asmprofiler/wiki/ProcessStackViewer

Вы можете попробовать memproof для отслеживания всех выделенных ресурсов (и их трассировки стека): http://www.torry.net/tools/debug/memory/memp0948.zip

person André    schedule 28.09.2010
comment
Я попытался создать подобное распределение памяти с помощью CoTaskMemAlloc (что сработало), но memproof не может их отслеживать. - person Harriv; 29.09.2010

Попробуйте EurekaLog, чтобы найти проблему.

person avra    schedule 29.09.2010
comment
См. Мой комментарий к Андре, то же самое относится к EurekaLog, а также к встроенному обнаружению утечек FastMM, поскольку выделение памяти не выполняется через диспетчер памяти Delphi (= FastMM). - person Harriv; 29.09.2010
comment
И да, я использую EurekaLog :) - person Harriv; 29.09.2010