debuggingmodulewindbgdebug-symbolssos

Windbg C# dump analysis: how to retrieve the module an object belongs to?


I have taken the memory dump of a running process (Task manager, right-click, "Create dump file", and now I'm investigating it using Windbg.

!Dumpheap -stat has revealed an enormous amount of objects, which seem to be collections of 14 entries: the end of the !Dumpheap -stat looks as follows (the first two columns contain hyperlinks):

3f62cc58 70b7d878       68     
3f62cc9c 70b7d878       68     
3f62cce0 70b7d878       68     
3f62cd24 70b7d878       68     
3f62cd68 70b7d878       68     

Clicking on such an object reveals the following:

0:000> !DumpObj /d 3f62ebb0
Name:        System.Object[]
MethodTable: 70b7d878
EEClass:     70754b80
Size:        68(0x44) bytes
Array:       Rank 1, Number of elements 14, Type CLASS (Print Array)
Fields:
None

Clicking on "Print Array" gives this:

0:000> !DumpArray /d 3f62ebb0
Name:        System.Object[]
MethodTable: 70b7d878
EEClass:     70754b80
Size:        68(0x44) bytes
Array:       Rank 1, Number of elements 14, Type CLASS
Element Methodtable: 70b7d824
[0] null
[1] 38f2cfd8
[2] null
[3] null
[4] null
[5] null
[6] null
[7] null
[8] null
[9] null
[10] null
[11] null
[12] null
[13] null

I would like to have more information, more especially what kind of collections those things are. In order to do that, I have thought of loading the debugging symbols and showing the module name.

I hope that, managing to configure the debugging symbol path, might reveal a lot of information.

Does anybody know how to do this?

Thanks in advance


Solution

  • I have taken the memory dump of a running process [...]

    To give better directions, it would be important to know why you created the memory dump. Just for fun, for learning or for doing a real analysis? If it's a real analysis, what kind of analysis? Do you want to find out about high memory usage, a hang, a performance issue (CPU spike) or does your application crash?

    [...] (Task manager, right-click, "Create dump file", and now I'm investigating it using Windbg.

    You didn't report any problems with your dump, but be aware that Task Manager is not necessarily the best choice. There are two versions of Task Manager, the 32 bit version and the 64 bit version and each of them takes the memory dump in that bitness. Check out other options for creating a crash dump, which might be better suitable, depending on the why question.

    !Dumpheap -stat has revealed an enormous amount of objects, [...]

    That's normal. A simple Hello World style WinForms application with an empty window has more than 5000 objects, when you might be thinking you only have 1 form.

    When you say "enormous", that's hard to put into context. It's better to be precise when it comes to debugging. Say "!Dumpheap lists 123.000.468 objects".

    the end of the !Dumpheap -stat looks as follows

    No, sorry. Either something is ultimately broken in your app or this is simply not the output of !dumpheap -stat. !dumpheap -stat has 4 columns:

    1. Type information (MT = Method Table)
    2. Object count
    3. Total size of all objects of that type
    4. Name of the object

    What you posted might be a part of the output of !dumpheap (without -stat). And that's typically not very useful, without prior knowledge of what one's looking for.

    [...] what kind of collections those things are

    Well, a System.Object[] is an array of type System.Object, typically declared in C# as object[]. There's nothing more to say about this collection.

    Other collections may be System.Windows.Forms.Control[] or 2D arrays like System.Int32[][] or System.Collections.Generic.List'1[[System.Windows.Forms.Application+ParkingWindow, System.Windows.Forms]] which is a generic List<ParkingWindow> in C# code.

    I have thought of loading the debugging symbols

    That's a very good idea. Without symbols, debugging is not worth it.

    Showing the module name : how do I do that?

    You can show modules with lm. lmv gives you version number and date information. lmf gives you the full path. You can filter for a specific module by appending m modulename. to any of the commands before.

    How can I see to which module an object belongs?

    That's not possible. Why? I have no reference, so let's make an educated guess.

    a) tracking the DLL of every small object would add at least a pointer size overhead. That might be 8 bytes for a 4 byte int. b) which DLL would you track? There are always several DLLs on the call stack. One module calls the other, which calls the next. Finally, you might always end up somewhere in a Microsoft DLL, because that's where strings, ints and a lot of stuff comes from. You don't want that. On the other extreme, the executable is the main reason why memory is allocated in the first place. So, it wouldn't exactly be simple to figure out which assemblies to track and which assemblies you don't want in that list. c) Looking at the call stack is quite an expensive operation. That's why throwing a lot of exceptions makes your application slow.

    All in all, I'd say it's not feasible to record a module to each object.

    The closest I can think of that has been implemented is Heap Tagging by DLL but that works with the Windows Heap Manager, which .NET doesn't use. Also, you just know which heap belongs to which DLL, not the objects.

    loading debugging symbols: how do I do that?

    Two steps should usually be sufficient:

    1. Use Microsoft symbols: .symfix
    2. Add your symbols: .sympath+ C:\some\directory

    For more details, see How to set up symbols, which explains more details.

    some "*.pdb" files

    Not some. Use all.

    C:\Temp_Folder\*

    You don't need to use wildcards. Just specify the directory.

    the modules stay deferred

    That's wanted. Loading symbols is slow. They will be loaded when needed. If you want to load them now, use ld * and get yourself a coffee while waiting.

    might reveal a lot of information.

    Sure. With debugging, you can get tons of information. You can have a look at everything. However, it's always good to know what you're looking for, when you have a haystack in front of you. That's still unclear to me. Why are you debugging? What are you looking for?