18. Januar 2009

.NET Dumps mit WinDbg analysieren

Mit WinDbg (Teil der Windows Debugging Tools) kann man auch .NET Dumps analysieren. Dazu muss es am besten mit der "Visual Studio Eingabeaufforderung" gestartet werden (so sind alle notwendigen Pfade automatisch gesetzt.

Dort kann einen zuvor mit adplus erstellten Dump laden.

Zunächst muss die Managed-Unterstützung geladen werden über die WinDbg-Kommadozeile
.loadby sos mscorwks
Eventuell fehlen hier Symbole. Sollte das der Fall sein, dann einfach im Menü File->Symbol Path auswählen und dort zusätzlich
http://msdl.microsoft.com/download/symbols
eintragen, dann werden die benötigten Symbole einfach von Microsoft heruntergeladen.


Sollte das System, auf dem der Dump gemacht wurde und das System, auf dem der Dump analysiert werden soll sich in der .NET Framework Version (auch nur minimal) unterscheiden, so muss die Datei mscordacwks.dll des gedumpten Systems in den Symbol-Pfad mit dem Namen
mscordacwks_<arch>_<arch>_<version>.dll
aufgenommen werden. (Siehe auch http://blogs.msdn.com/b/tom/archive/2008/04/09/asp-net-tips-getting-sos-to-work-when-commands-fail.aspx)


Heap analysieren
!DumpHeap
liefert z.B.: folgende Ausgabe:
MT    Count    TotalSize Class Name
6ef5fba8       73         4088 System.Reflection.RuntimeMethodInfo
68634fb4       28         4144 System.Data.DataColumn
68df1488       61         4392 System.Windows.Forms.PropertyStore+ObjectEntry[]
6ef60508      392         4704 System.Object
6ef62f40       92         5152 System.Collections.Hashtable
68635d88        5         5180 System.Data.RBTree`1+Node[[System.Data.DataRow, System.Data]][]
6b5f8c4c       95         5320 System.Configuration.FactoryRecord
6ef62a88       89         5576 System.Int32[]
6ef4c47c      230         6440 System.Security.SecurityElement
6ef61a6c      369         7380 System.RuntimeType
6ef6151c       81         9880 System.Char[]
68636e00       10        10360 System.Data.RBTree`1+Node[[System.Int32, mscorlib]][]
6ef6335c       79        17652 System.Byte[]
6ef6303c       93        21240 System.Collections.Hashtable+bucket[]
6ef62b38     4643        55716 System.Int32
68636f00     2311        64708 System.Data.RBTree`1+RBTreeEnumerator[[System.Data.DataRow, System.Data]]
6ef340bc      627        75216 System.Object[]
6ef5a930     2328        83808 System.Collections.Hashtable+HashtableEnumerator
68df5158     9246       110952 System.Windows.Forms.Control+MultithreadSafeCallScope
6ef6291c     5017       120408 System.Collections.ArrayList
6ef62c14     4622       129416 System.Collections.ArrayList+ArrayListEnumeratorSimple
6ef60a28    11593       231860 System.Text.StringBuilder
6ef608ec    18367      1163300 System.String


Dump aller Objekte im LargeObjectHeap
!dumpheap -min 85000



Threadstack analysieren
Liste der CLR Threads
!threads
anzegen:
PreEmptive   GC Alloc           Lock
ID OSID ThreadOBJ    State     GC       Context       Domain   Count APT Exception
0    1 10c4 0026a4f0      6020 Enabled  0211b030:0211ca74 00266280     0 STA
2    2 1124 002779c0      b220 Enabled  00000000:00000000 00266280     0 MTA (Finalizer)
3    3 1360 002f4078   880b220 Enabled  00000000:00000000 00266280     0 MTA (Threadpool Completion Port)
4    4 1368 002f6d58    80a220 Enabled  00000000:00000000 00266280     0 MTA (Threadpool Completion Port)


Dort wählt man sich den gewünschten Thread aus über
~<ID>s
, also um den Thread mit der ID 0 anzuschauen gibt man
~0s
ein. Dann kann man sich mit
!CLRStack
nur Managed Stack ausgeben lassen, was z.B. zu folgender Ausgaben führt:
SharpShutdown+0x1632e (012f632e)
Priority: 0  Priority class: 32  Affinity: 3
0:000> !clrstack -p
OS Thread Id: 0x10c4 (0)
ESP       EIP
0016f240 775a9a94 [InlinedCallFrame: 0016f240] System.Windows.Forms.UnsafeNativeMethods.WaitMessage()
0016f23c 68da8e48 System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32, Int32, Int32)
PARAMETERS:
this = 0x01f68694
dwComponentID = 
reason = 0xffffffff
pvLoopData = 0x00000000

0016f2d8 68da8937 System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)
PARAMETERS:
this = 0x01f3ef78
reason = 0xffffffff
context = 0x01f634b8

0016f32c 68da8781 System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)
PARAMETERS:
this = 
reason = 
context = 

0016f35c 68d65911 System.Windows.Forms.Application.Run(System.Windows.Forms.Form)
PARAMETERS:
mainForm = 

0016f370 00eac769 DE.RFeest.Tools.SharpShutdown.Program.Main()

CPU-Zeit der einzelnen Threads
!runaway
User Mode Time
Thread       Time
12:1818      0 days 0:02:46.359
25:1164      0 days 0:02:42.859
31:1d54      0 days 0:01:05.421
33:140c      0 days 0:01:03.031
34:794       0 days 0:00:55.562
30:120c      0 days 0:00:53.031
32:1980      0 days 0:00:49.937
37:1900      0 days 0:00:42.640
38:1dc8      0 days 0:00:41.984
17:1da0      0 days 0:00:35.156
14:1bb0      0 days 0:00:34.937
15:1848      0 days 0:00:34.546
16:8fc       0 days 0:00:34.109
39:1398      0 days 0:00:29.140
35:7f4       0 days 0:00:27.015
40:1270      0 days 0:00:26.625
36:1908      0 days 0:00:17.781
Details zu einer Managed-Exeception
29   18 1458 2039df38   180b220 Enabled  0e15d56c:0e15d57c 00109f58     3 MTA (Threadpool Worker) System.OutOfMemoryException (05c6c578)
kann man sich über
!pe
anzeigen lassen:
Exception object: 126449bc
Exception type: System.OutOfMemoryException
Message: 
InnerException: 
StackTrace (generated):
SP       IP       Function
7C7EE5A4 792F110C mscorlib_ni!System.Reflection.Assembly.nLoad(System.Reflection.AssemblyName, System.String, System.Security.Policy.Evidence, System.Reflection.Assembly, System.Threading.StackCrawlMark ByRef, Boolean, Boolean)+0x2c
7C7EE5CC 792D5B58 mscorlib_ni!System.Reflection.Assembly.InternalGetSatelliteAssembly(System.Globalization.CultureInfo, System.Version, Boolean)+0xd8
7C7EE5F0 792D4000 mscorlib_ni!System.Resources.ResourceManager.GetSatelliteAssembly(System.Globalization.CultureInfo)+0x50
7C7EE61C 792821AC mscorlib_ni!System.Resources.ResourceManager.InternalGetResourceSet(System.Globalization.CultureInfo, Boolean, Boolean)+0x12c
7C7EE670 792822C8 mscorlib_ni!System.Resources.ResourceManager.InternalGetResourceSet(System.Globalization.CultureInfo, Boolean, Boolean)+0x248
7C7EE6C4 7928190B mscorlib_ni!System.Resources.ResourceManager.GetString(System.String, System.Globalization.CultureInfo)+0x4b
7C7EE6E4 6522C3ED System_Data_ni!System.Data.Res.GetString(System.String)+0x1d
7C7EE6F0 654CD912 System_Data_ni!System.Data.Common.ADP.PooledOpenTimeout()+0x12
7C7EE700 656C70B4 System_Data_ni!System.Data.ProviderBase.DbConnectionFactory.GetConnection(System.Data.Common.DbConnection)+0x4a36e4
7C7EE720 65223846 System_Data_ni!System.Data.ProviderBase.DbConnectionClosed.OpenConnection(System.Data.Common.DbConnection, System.Data.ProviderBase.DbConnectionFactory)+0x76
7C7EE754 6521DF06 System_Data_ni!System.Data.SqlClient.SqlConnection.Open()+0xf6
...
StackTraceString: 
HResult: 8007000e
Anaylse von aufgezeichneten Exceptions Wenn folgendes von windbg ausgegeben wird:
This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.
kann man eine Analyse dieser Exception ausführen:
!analyze -v
Siehe auch: http://msdn.microsoft.com/en-us/magazine/cc163528.aspx http://www.informit.com/articles/article.aspx?p=1409801&seqNum=4 http://msdn.microsoft.com/en-us/library/bb190764.aspx http://blogs.msdn.com/b/alejacma/archive/2009/08/13/managed-debugging-with-windbg-managed-heap-part-1.aspx http://www.zhaun.net/post/Debugging-NET-virtual-memory-fragmentation-with-WinDbg.aspx http://www.codeproject.com/KB/dotnet/BestPractices5.aspx#WhatisthetypeofmemoryleakTotalMemoryManagedmemoryunmanagedmemory

Keine Kommentare: