MANAGED DEBUGGING with WINDBG. Managed Heap. Part 2

Hi all,

This post is a continuation of MANAGED DEBUGGING with WINDBG. Managed Heap. Part 1.

MANAGED HEAP. Part 2

· We can take a look to the objects in the heap:

We can see all objects in the heap:

0:004> !DumpHeap

Address MT Size

7b463c40 790fd0f0 12

7b463c4c 790fd8c4 36

7b463c70 790fd8c4 20

...

01905378 79119a1c 32

...

02907de0 003d6d48 16 Free

total 12400 objects

Statistics:

MT Count TotalSize Class Name

7b492254 1 12 System.Windows.Forms.VisualStyles.VisualStyleRenderer+ThemeHandle

...

79119a1c 3 96 System.Security.Policy.PermissionRequestEvidence

...

003d6d48 11 164 Free

...

790fd0f0 165 1980 System.Object

...

790fd8c4 7308 435252 System.String

Total 12400 objects

0:004> !do 01905378

Name: System.Security.Policy.PermissionRequestEvidence

...

0:004> !do 02907de0

Free Object

Size 16(0x10) bytes

Note the existence of Free objects in the heap. The Free entry represents objects which are not referenced and have been garbage collected, but whose memory hasn't been compacted and released to the operating system yet. These regions of space can be re-used by the Garbage Collector later. If 30% or more of the heap contains Free objects, the process may suffer from heap fragmentation.

I’m sure we noticed that there are too many objects in the heap, so it’s usually better to see only the statistics:

0:004> !DumpHeap -stat

total 12400 objects

Statistics:

MT Count TotalSize Class Name

7b492254 1 12 System.Windows.Forms.VisualStyles.VisualStyleRenderer+ThemeHandle

...

79119a1c 3 96 System.Security.Policy.PermissionRequestEvidence

...

003d6d48 11 164 Free

...

790fd0f0 165 1980 System.Object

...

790fd8c4 7308 435252 System.String

Total 12400 objects

We can also focus on the objects of a given type only:

0:004> !Name2EE * System.Security.Policy.PermissionRequestEvidence

Module: 790c2000 (mscorlib.dll)

Token: 0x0200048a

MethodTable: 79119a1c

...

0:004> !DumpHeap -mt 79119a1c

Address MT Size

01901ebc 79119a1c 32

01905378 79119a1c 32

019290c0 79119a1c 32

total 3 objects

Statistics:

MT Count TotalSize Class Name

79119a1c 3 96 System.Security.Policy.PermissionRequestEvidence

Total 3 objects

Or focus on objects of several types with part of the name in common:

0:004> !DumpHeap -type System.Security.Policy

Address MT Size

01901b78 7910ed68 20

...

01901ebc 79119a1c 32

...

0192971c 79119bf4 16

total 38 objects

Statistics:

MT Count TotalSize Class Name

791197b0 1 12 System.Security.PolicyManager

7911c924 1 24 System.Security.Policy.Hash

...

79119a1c 3 96 System.Security.Policy.PermissionRequestEvidence

...

790f97c4 3 156 System.Security.Policy.PolicyLevel

Total 38 objects

We can see the objects in the Large Object Heap, and we can do it in several ways:

0:004> !EEHeap -GC

Number of GC Heaps: 1

generation 0 starts at 0x01901018

generation 1 starts at 0x0190100c

generation 2 starts at 0x01901000

ephemeral segment allocation context: none

segment begin allocated size

00423878 7b463c40 7b47a744 0x00016b04(92932)

0041d178 7a733370 7a754b98 0x00021828(137256)

003d6600 790d8620 790f7d8c 0x0001f76c(128876)

01900000 01901000 01949ff4 0x00048ff4(298996)

Large object heap starts at 0x02901000

segment begin allocated size

02900000 02901000 02907df0 0x00006df0(28144)

Total Size 0xa787c(686204)

------------------------------

GC Heap Size 0xa787c(686204)

0:004> !DumpHeap 02901000 02907df0

Address MT Size

02901000 003d6d48 16 Free

02901010 7912d8f8 4096

...

total 15 objects

Statistics:

MT Count TotalSize Class Name

003d6d48 8 128 Free

7912d8f8 7 28016 System.Object[]

Total 15 objects

0:004> !SOS.DumpHeap -min 85000

...

Note that there are objects in LOH which size is smaller than 85,000 bytes (?).

We can also see the objects which are ready for finalization, and in general, which objects in our app have a Finalize method:

0:004> !FinalizeQueue

SyncBlocks to be cleaned up: 0

MTA Interfaces to be released: 0

STA Interfaces to be released: 0

----------------------------------

generation 0 has 703 finalizable objects (00457998->00458494)

generation 1 has 0 finalizable objects (00457998->00457998)

generation 2 has 0 finalizable objects (00457998->00457998)

Ready for finalization 0 objects (00458494->00458494)

Statistics:

MT Count TotalSize Class Name

7b492254 1 12 System.Windows.Forms.VisualStyles.VisualStyleRenderer+ThemeHandle

...

7ae77fa8 2 80 System.Drawing.Icon

...

7b485894 59 3776 System.Windows.Forms.Internal.DeviceContext

Total 703 objects

0:004> dd 00457998 00458494-4

00457998 01901f10 01905238 01906414 01906428

...

00457b28 019323f8 019324b0 0193296c 01936378

...

00458488 01949468 019494f0 0194959c

0:004> !DumpHeap -mt 7ae77fa8

Address MT Size

0193296c 7ae77fa8 40

01936378 7ae77fa8 40

total 2 objects

Statistics:

MT Count TotalSize Class Name

7ae77fa8 2 80 System.Drawing.Icon

Total 2 objects

0:004> !do 0193296c

Name: System.Drawing.Icon

...

0:004> !DumpMT -md 7ae77fa8

...

Name: System.Drawing.Icon

...

--------------------------------------

MethodDesc Table

Entry MethodDesc JIT Name

...

7ae2070c 7aea3c88 PreJIT System.Drawing.Icon.Finalize()

...

7ae201dc 7aea3c58 PreJIT System.Drawing.Icon.Dispose()

...

Look to the way Reflector.exe shows the Dispose and Finalize (destructor) methods of the “Icon” class we saw above, and how Dispose tells the GC to forget about the Finalize method:

public void Dispose()

{

this.Dispose(true);

GC.SuppressFinalize(this);

}

~Icon()

{

this.Dispose(false);

}

We can get extra information on the following objects registered for finalization: SyncBlocks and RuntimeCallableWrappers (RCWs). Both of these data structures are cached and cleaned up by the Finalizer thread.

0:000> !FinalizeQueue -detail

To be cleaned Com Data

0x4edc1b8 ComPlusWrapper

0x4edc590 ComPlusWrapper

...

0x4e227b8 ComPlusWrapper

SyncBlock to be cleaned up: 6371

MTA interfaces to be released: 0

STA interfaces to be released: 0

...

Every time a COM interface pointer enters the CLR, it is wrapped in a RCW. The RCW has a reference count that is incremented every time a COM interface pointer is mapped to it. The System.Runtime.InteropServices.Marshal.ReleaseComObject method decrements the reference count. If the same COM interface is passed more than once from unmanaged to managed code, the reference count on the wrapper is incremented every time and calling ReleaseComObject returns the number of remaining references. When the reference count reaches zero, the runtime releases all its references on the unmanaged COM object. We use this method to free the COM object and the resources it holds.

Next post: MANAGED DEBUGGING with WINDBG. Managed Heap. Part 3.

Index: MANAGED DEBUGGING with WINDBG. Introduction and Index.

Regards,

Alex (Alejandro Campos Magencio)