Finding the Root Cause of a .Net Application Memory Leak

Overview

High memory use in a .Net application is usually the result of Common Language Runtime (CLR) objects growing in size continuously. When the application memory use grows to over 1.4GB in size, the next time the application tries to “New” an object it will hit a CLR exception of type System.OutOfMemoryException causing the application to crash. The CLR memory is not really “leaked” like it could be in a C program that uses malloc() to get a handle to a memory address and does not free it before going out of scope, causing the memory location to be unusable again in the lifetime of the program. All .Net memory allocations are managed by the CLR garbage collector, so it knows about the location and size. Luckily, these large objects can’t be hidden, and there are tools to analyze a .Net application to find collections that are 1) large in size and 2) continue growing throughout the lifetime of the process. In this article, we use these tools to find the source of a .Net application that continually grows in size or “leaks.”

Summary

The new release of the ACME RocketSled Desktop 5.0 process Org.ACME.RocketSledDesktop.exe climbs in memory usage in nine hours of continuous use. We need to investigate the process memory usage to determine which internal objects are consuming the memory. These investigative steps are meant to be a guide to where to further investigate the source code for the root cause. The development team will take these results and use them to focus on the resulting objects to fix the memory use issue.

Methodology

We take a snapshot of memory utilization during two different times while the application is running. Note that these two snapshots should both be after the application under test is already warmed up. Then, we use the tools below to narrow our focus to the CLR classes, then to the objects, and finally to the reference owners of the objects.

Tools

RocketSled is a managed application, so we suspect the memory usage is in the CLR Garbage Collected (GC) Heap. To analyze this, we use publicly available Microsoft tools Console Debugger (CDB) and Son of Strike (SOS). To get the process in a memory using state, we run a UI automation test script and save a process dump after about one hour and then again after about two hours. This can also be done with a live process instead of a dump, but the process dumps can be saved and debugged offline anytime in the future without interrupting the machine running the test. To learn how to use CDB and save process dumps, please read the document Orasi published titled Debugging Windows Crashes with Microsoft Debugging Tools – Tutorial.

Discoveries

The GC Heap was using about 53MB after the first hour and 57MB after the second hour, a small increase but on an upward trend like we expected. The objects consuming most of the heap are System.Byte[] and System.String as represented below at the two-hour mark. They are sorted and descending by size. We truncated this list with just these six rows, but the inclusive list adds up to 57MB.

MT

Count

TotalSize

Class Name

79ba4aa0

4,454

14,403,816

System.Byte[]

79b9fb08

105,553

6,073,728

System.String

79b56d84

41,728

1,911,032

System.Object[]

79ba55d8

4,133

1,047,984

System.Collections.Hashtable+bucket[]

58cfe3b4

10,845

902,836

System.Windows.EffectiveValueEntry[]

56d13de4

16,712

742,912

System.Windows.ChildValueLookup[]

 

The next step is to find out what is holding references to these objects. Many of these ACME-owned objects are used to store data and have String or Byte[] properties. Notice that the reference count of these is climbing between the first hour and second hour. If we look at data from a full nine-hour run, we can guess that that they would be much higher. For example 112 – 75 = 37 per hour. 9hrs * 37 = 333.

Objects (ACME) Count 1hr Count 2hrs
1acd2a38(Org.ACME.WileE.CoyoteBannerModel)-> 75 112
152e0d70(Org.ACME.ApplicationObjects.User)-> 75 112
00db9010(Org.ACME.RocketSledDesktop.RocketSledDesktopWIndow)-> 75 111
00dd4cb8(Org.ACME.WileE.Views.Authentication.AuthenticationView)-> 75 111
1ac2df70(Org.ACME.WileE.CoyoteWorkspaceHost)-> 75 111
00dc2e0c(Org.ACME.RocketSledShell.RocketSledShellView)-> 75 111
152e4868(Org.ACME.CoyoteManagement.CoyoteModel)-> 75 104
1ac2afcc(Org.ACME.WileE.CoyoteWorkspace)-> 75 93
1ac2b024(Org.ACME.WileE.ComponentUtilizationServiceClient)-> 75 86

Now, looking at the reference chain to System.Byte[], we find a very large list. Filtering by Org.ACME and sorting by the most common objects in the chain, we find a reasonably sized list.

Then, we go back and look at the raw output of the reference chain to System.Byte[] and find the most commonly occurring Org.ACME objects and determine that the closest reference to System.Byte[] in an ACME object is usually Org.ACME.CoyoteManagement.CoyoteModel, which we believe could be the object that is being held in memory causing the memory usage. Also, on the top of the chain is what appears to be a timer event, System.Windows.Media.Animation.TimeManager, not a direct call from an explicit user action. We recommend that development look at the reference chain below and determine in the source code where Org.ACME.CoyoteManagement.CoyoteModel and the other ACME objects are being created and disposed and inspect them to make sure they are being properly disposed. Here is one of many of the above mentioned reference chains.

Common Reference Chain to System.Byte[]

ebx:Root:  00dc5d50(System.Windows.Media.Animation.TimeManager)->
  00dc5784(System.Windows.Media.MediaContext)->
  00dc591c(System.Collections.Generic.Dictionary`2[[System.Windows.Media.ICompositionTarget, PresentationCore],[System.Object, mscorlib]])->
  00ea9468(System.Collections.Generic.Dictionary`2+Entry[[System.Windows.Media.ICompositionTarget, PresentationCore],[System.Object, mscorlib]][])->
  00ea91f4(System.Windows.Interop.HwndTarget)->
  00db9010(Org.ACME.RocketSledDesktop.RocketSledDesktopWIndow)->
  00dc2e0c(Org.ACME.RocketSledShell.RocketSledShellView)->
  00dd4cb8(Org.ACME.WileE.Views.Authentication.AuthenticationView)->
  00ea652c(System.Windows.Controls.TextBlock)->
  00ea63b0(System.Windows.Controls.StackPanel)->
  00e61288(System.Windows.Controls.StackPanel)->
  00e62944(System.Windows.Controls.UIElementCollection)->
  00e62958(System.Windows.Media.VisualCollection)->
  00ea64b8(System.Object[])->
  00ea11f0(System.Windows.Controls.StackPanel)->
  00ea1498(System.Windows.Controls.UIElementCollection)->
  00ea14ac(System.Windows.Media.VisualCollection)->
  00ea3710(System.Object[])->
  00ea15d4(System.Windows.Controls.Image)->
  01619384(System.Windows.EffectiveValueEntry[])->
  0100910c(System.Windows.Automation.Peers.ImageAutomationPeer)->
  01008b00(System.Windows.Automation.Peers.UserControlAutomationPeer)->
  01008a90(System.Windows.Automation.Peers.UserControlAutomationPeer)->
  1cdec464(System.Collections.Generic.List`1[[System.Windows.Automation.Peers.AutomationPeer, PresentationCore]])->
  1cdec47c(System.Object[])->
  155e5b08(System.Windows.Automation.Peers.UserControlAutomationPeer)->
  1cdecf28(System.Collections.Generic.List`1[[System.Windows.Automation.Peers.AutomationPeer, PresentationCore]])->
  1cdecf60(System.Object[])->
  1b062404(System.Windows.Automation.Peers.UserControlAutomationPeer)->
  1ac2df70(Org.ACME.WileE.CoyoteWorkspaceHost)->
  1ac2afcc(Org.ACME.WileE.CoyoteWorkspace)->
  1ac2b024(Org.ACME.WileE.ComponentUtilizationServiceClient)->
  152e0d70(Org.ACME.ApplicationObjects.User)->
  1adc5878(System.ComponentModel.PropertyChangedEventHandler)->
  1adc5860(System.Object[])->
  1adc5840(System.ComponentModel.PropertyChangedEventHandler)->
  1acd2a38(Org.ACME.WileE.CoyoteBannerModel)->
  152e4868(Org.ACME.CoyoteManagement.CoyoteModel)->
  1b513c40(System.ComponentModel.PropertyChangedEventHandler)->
  1b513c28(System.Object[])->
  1b513c08(System.ComponentModel.PropertyChangedEventHandler)->
  1b513bd8(MRPQL.MRPQLViewModel)->
  1b7aa524(MRPQL.MRPQLViewModel+ReadyEventHander)->
  1b513a38(MRPQL.MRPQLWindow)->
  1b528f64(System.Windows.Controls.Primitives.ToggleButton)->
  1b52ced0(System.Windows.EffectiveValueEntry[])->
  1b7a2320(System.Windows.ModifiedValue)->
  1b52ce54(System.Windows.Data.BindingExpression)->
  00dca6a8(MS.Internal.Data.DataBindEngine)->
  017ee558(System.Windows.Controls.ContentControl)->
  01ba64b8(System.Windows.EffectiveValueEntry[])->
  017ef238(System.Windows.DataTemplate)->
  017ef73c(System.Windows.TemplateContent)->
  017ef764(System.Windows.TemplateLoadData)->
  017ef7ec(System.Windows.TemplateContent+ServiceProviderWrapper)->
  017ef390(MS.Internal.Xaml.ServiceProviderContext)->
  017ef128(MS.Internal.Xaml.Context.ObjectWriterContext)->
  017ef164(MS.Internal.Xaml.Context.XamlContextStack`1[[MS.Internal.Xaml.Context.ObjectWriterFrame, System.Xaml]])->
  017ef1b8(MS.Internal.Xaml.Context.ObjectWriterFrame)->
  0170deb4(MS.Internal.Xaml.Context.ObjectWriterFrame)->
  0170def4(MS.Internal.Xaml.Context.ObjectWriterFrame)->
  01437a6c(System.Windows.ResourceDictionary)->
  01437b94(System.Windows.ResourceDictionaryCollection)->
  01437bc0(System.Collections.Generic.List`1[[System.Windows.ResourceDictionary, PresentationFramework]])->
  016ae63c(System.Object[])->
  016cb3bc(System.Windows.ResourceDictionary)->
  016cdb4c(System.Windows.ResourceDictionaryCollection)->
  016cdb78(System.Collections.Generic.List`1[[System.Windows.ResourceDictionary, PresentationFramework]])->
  016cdccc(System.Object[])->
  016dcbd8(System.Windows.ResourceDictionary)->
  016f42f4(System.Windows.Baml2006.Baml2006Reader)->
  016f4544(System.Windows.Baml2006.BamlBinaryReader)->
  016f44fc(System.Windows.Baml2006.SharedStream)->
  016f4080(System.IO.MemoryStream)->
  027660c8(System.Byte[])

Steps to Analyze

We are providing some overview steps as a guide to performing this analysis on a similar memory use issue. The CLR objects and addresses will be different, but the methodology is the same.

Attach/Load Dump File

We have the two process dumps, and we can load the first one as follows.

cdb –z RocketSled1.dmp

Load SOS

Then, we need to load SOS to debug managed code. This command loads it from the same location as the CLR.

0:039> .loadby sos clr

EEHeap

We use “!eeheap -gc” to display a summary of the GC Heaps. We see that the “.NET CLR Memory\# Bytes in all Heaps” is up to 53,678,732 bytes or 53 MB.

0:039> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x1afbebac
generation 1 starts at 0x1af7d708
generation 2 starts at 0x00d91000
ephemeral segment allocation context: none
 segment     begin allocated  size
00d90000  00d91000  01d8c260  0xffb260(16,757,344)
14eb0000  14eb1000  15e77644  0xfc6644(16,541,252)
1ab00000  1ab01000  1b477440  0x976440(9,921,600)
Large object heap starts at 0x01d91000
 segment     begin allocated  size
01d90000  01d91000  0278a5a8  0x9f95a8(10,458,536)
Total Size:              Size: 0x333128c (53,678,732) bytes.
------------------------------
GC Heap Size:            Size: 0x333128c (53,678,732) bytes.

DumpHeap -stat

To find out more, we need to find out what type of objects are in the heap. From the “!dumpheap -stat” output we will pick the biggest contributor to the heap and see if we can find who owns those objects. In this case, it is the System.Byte[].

0:039> !dumpheap -stat
total 0 objects
Statistics:
      MT    Count    TotalSize Class Name
…
79ba55d8     3052       798696 System.Collections.Hashtable+bucket[]
79b56d84    33474      1507180 System.Object[]
79b9fb08    83435      4888840 System.String
79ba4aa0     3722     10253640 System.Byte[]
00177578     8013     22125252      Free
Total 509385 objects
0:039>

DumpHeap -mt

In order to find out who owns the System.Byte[], we first need to get some object addresses using “!dumpheap -mt” which will dump out all the object addresses for the specified type. There’s no real need to see all 30,000 addresses, so it’s okay to <ctrl><c> to interrupt the output.

0:039> !dumpheap -mt 79ba4aa0
 Address       MT     Size
00d9ace4 79ba4aa0      524     
00d9ea04 79ba4aa0       12     
00d9f578 79ba4aa0      268     
00d9fa98 79ba4aa0       28     
00d9faec 79ba4aa0      140
…
0258a0b0 79ba4aa0   119632     
025a7410 79ba4aa0    93808     
025be290 79ba4aa0    93808     
025d5110 79ba4aa0   148704     
026a4988 79ba4aa0    93808     
026bb808 79ba4aa0    93808     
026d2688 79ba4aa0   148704     
026f6b78 79ba4aa0   148704     
0271b068 79ba4aa0   119632     
027383c8 79ba4aa0    93808     
0274f248 79ba4aa0    93808     
027660c8 79ba4aa0   148704
0:039>

GCRoot

Now that we have some object addresses to look at, let’s see who owns the objects. We choose address 027660c8, because it is one of the largest in the list above. We could have chosen another such as 026d2688 or 026f6b78.

0:039> !gcroot 027660c8
Scan Thread 0 OSTHread 1b34
ESP:12f1b0:Root:  00d9d78c(System.Windows.Threading.DispatcherFrame)->
  00d9cc78(System.Windows.Threading.Dispatcher)->
  00db9968(System.Windows.Input.InputManager)->
  00db9f60(System.Windows.Input.StylusLogic)->
  00dba098(System.Collections.Generic.Dictionary`2[[System.Object, mscorlib],[System.Windows.Input.PenContexts, PresentationCore]])->
  00dba0e4(System.Collections.Generic.Dictionary`2+Entry[[System.Object, mscorlib],[System.Windows.Input.PenContexts, PresentationCore]][])->
  00ea8dc8(System.Windows.Interop.HwndSource)->
  00db9220(Org.ACME.RocketSledDesktop.RocketSledDesktopWIndow)->
  00dc3080(Org.ACME.RocketSledShell.RocketSledShellView)->
  00dd4f4c(Org.ACME.WileE.Views.Authentication.AuthenticationView)->
  00ea655c(System.Windows.Controls.TextBlock)->

We sort the output of “!gcroot 027660c8” and look at what has occurred most often containing “Org.ACME,” and the following is the result. This is easy to calculate by pasting into Excel and using a pivot table to group.

Call Count
1510d634(Org.ACME.WileE.CoyoteBannerModel)-> 74
01924fdc(Org.ACME.ApplicationObjects.User)-> 74
00dc3080(Org.ACME.RocketSledShell.RocketSledShellView)-> 73
00dd4f4c(Org.ACME.WileE.Views.Authentication.AuthenticationView)-> 73
00db9220(Org.ACME.RocketSledDesktop.RocketSledDesktopWIndow)-> 73
019274c4(Org.ACME.CoyoteManagement.CoyoteModel)-> 73
150661dc(Org.ACME.WileE.CoyoteWorkspaceHost)-> 72
15062fac(Org.ACME.WileE.ComponentUtilizationServiceClient)-> 54
15062f54(Org.ACME.WileE.CoyoteWorkspace)-> 54
1aef9fd0(Org.ACME.WileE.CompositeView.JWPanel2)-> 18
1ab24094(System.Collections.Generic.Dictionary`2+Entry[[Org.ACME.WileE.CompositeView.JWPanel, Org.ACME.WileE.CompositeView],[System.Int32, mscorlib]][])-> 18
1521c4b8(System.Collections.Generic.Dictionary`2[[Org.ACME.WileE.CompositeView.JWPanel, Org.ACME.WileE.CompositeView],[System.Int32, mscorlib]])-> 18
1521c384(Org.ACME.WileE.CompositeView.JWKeyHoleHost)-> 18
00f6ecf4(Org.ACME.ApplicationObjects.Session)-> 15
15abf01c(System.Collections.ObjectModel.ObservableCollection`1[[Org.ACME.Vitalsigns.Models.VitalSignsRecord, Org.ACME.Vitalsigns]])-> 11
14fbf760(Org.ACME.WileE.Views.Help2SelectCoyoteView)-> 2
00f25c20(Org.ACME.ApplicationObjects.OrganizationalUnit)-> 1

DumpObj

First, we look at the object Org.ACME.WileE.CoyoteBannerModel at address 1510d634.

0:039> !do 1510d634
Name:        Org.ACME.WileE.CoyoteBannerModel
MethodTable: 034be4f8
EEClass:     0e8f1554
Size:        52(0x34) bytes
File:        C:\Program Files\ACME\WileE\Org.ACME.WileE.CoyoteBanner.dll
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
7aa055f4  4000001        4 ...angedEventHandler  0 instance 1510ddfc PropertyChanged
7aa02b58  4000002        8 ...fyPropertyChanged  0 instance 01ae41dc CoyoteContainerObject
7aa02b58  4000003        c ...fyPropertyChanged  0 instance 019274c4 CoyoteAlertsContainerObject
7aa02b58  4000004       10 ...fyPropertyChanged  0 instance 01924fdc userRoleContainerObject
79b9fb08  4000005       14        System.String  0 instance 150669b4 CoyoteRetrievalPropertyName
79b9fb08  4000006       18        System.String  0 instance 150669dc CoyoteAlertsRetrievalPropertyName
79b9fb08  4000007       1c        System.String  0 instance 0109a408 userRoleRetrievalPropertyName
0cf2d24c  4000008       20 ...onObjects.Coyote  0 instance 1554cb60 activeCoyote
0cf238dc  4000009       24 ...licationObjects]]  0 instance 019274e8 CoyoteAlerts
04392fd4  400000a       28 ...ationObjects.Role  0 instance 019f446c userRole
79b90a5c  400000b       2c         System.Int32  1 instance       28 propertyRetrievalFlags

ObjSize

Adding all the object sizes referencing Org.ACME.WileE.CoyoteBannerModel contribute 23MB of the 53MB GC Heap.

0:039> !objsize 1510d634
sizeof(1510d634) =     23323732 (   0x163e454) bytes (Org.ACME.WileE.CoyoteBannerModel)
0:039>

DumpObj

Second, Org.ACME.ApplicationObjects.User.

0:039> !do 01924fdc
Name:        Org.ACME.ApplicationObjects.User
MethodTable: 04392c34
EEClass:     042ac5f4
Size:        44(0x2c) bytes
File:        C:\Program Files\ACME\WileE\Org.ACME.ApplicationObjects.dll
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
7aa055f4  4000001        4 ...angedEventHandler  0 instance 1521d114 PropertyChanged
04392fd4  4000076        8 ...ationObjects.Role  0 instance 019f446c _currentRole
0d944964  4000077        c ...licationObjects]]  0 instance 019f4410 _roles
79b9fb08  4000078       10        System.String  0 instance 01923cb8 <FirstName>k__BackingField
79b9fb08  4000079       14        System.String  0 instance 01923b9c <LastName>k__BackingField
79b9fb08  400007a       18        System.String  0 instance 019244f4 <UserId>k__BackingField
79b9fb08  400007b       1c        System.String  0 instance 01924ca8 <UnitNumber>k__BackingField
79ba6788  400007c       24       System.Boolean  1 instance        0 <IsAdmin>k__BackingField
79b9fb08  400007d       20        System.String  0 instance 01924b84 <UserNCID>k__BackingField

ObjSize

0:039> !objsize 01924fdc
sizeof(01924fdc) =     23323732 (   0x163e454) bytes (Org.ACME.ApplicationObjects.User)

DumpObj

Third, Org.ACME.RocketSledShell.RocketSledShellView.

0:039> !do 00dc3080
Name:        Org.ACME.RocketSledShell.RocketSledShellView
MethodTable: 0359005c
EEClass:     03521f88
Size:        276(0x114) bytes
File:        C:\Program Files\ACME\WileE\Org.ACME.RocketSledShell.dll
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
58cf50f4  4000dbc        4 ...eading.Dispatcher  0 instance 00d9cc78 _dispatcher
…
79ba6788  4000009       f3       System.Boolean  1 instance        1 _contentLoaded
04391818  400000a        4 ...er+ThreadDelegate  0   static 011b7de8 CS$<>9__CachedAnonymousMethodDelegate2
ObjSize
0:039> !objsize 00dc3080
sizeof(00dc3080) =     23323732 (   0x163e454) bytes (Org.ACME.RocketSledShell.RocketSledShellView)

Attach/Load dump file

We now look at the same data after another hour of runtime. We can load the second process dump as follows:

cdb –z RocketSled2.dmp

SOS

Then we load SOS to debug managed code. This command loads it from the same location as the CLR.

0:039> .loadby sos clr

EEHeap

The heap has grown by 3MB in an hour. Not much, but if it continues this way, we have a leak.

0:000> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x1cb6b0c8
generation 1 starts at 0x1cae1000
generation 2 starts at 0x00d91000
ephemeral segment allocation context: none
 segment     begin allocated  size
00d90000  00d91000  01d725f4  0xfe15f4(16651764)
14eb0000  14eb1000  15b83da8  0xcd2da8(13446568)
1ab00000  1ab01000  1b82ae54  0xd29e54(13803092)
1cae0000  1cae1000  1ce05e48  0x324e48(3296840)
Large object heap starts at 0x01d91000
 segment     begin allocated  size
01d90000  01d91000  027a1418  0xa10418(10552344)
Total Size:              Size: 0x3713450 (57750608) bytes.
------------------------------
GC Heap Size:            Size: 0x3713450 (57,750,608) bytes.

DumpHeap

0:035> !dumpheap -stat
total 0 objects
Statistics:
      MT    Count    TotalSize Class Name
…
56d19340    21286       681152 System.Windows.Baml2006.KeyRecord
56d13de4    16712       742912 System.Windows.ChildValueLookup[]
58cfe3b4    10845       902836 System.Windows.EffectiveValueEntry[]
79ba55d8     4133      1047984 System.Collections.Hashtable+bucket[]
79b56d84    41728      1911032 System.Object[]
79b9fb08   105553      6073728 System.String
79ba4aa0     4454     14403816 System.Byte[]
00177578     3787     15291084      Free
Total 674273 objects

DumpHeap -mt

This will be similar output to the first hour so not including output here.

GCRoot

Now that we have some object addresses to look at, let’s see who owns the objects.

0:039> !gcroot 027660c8

References for these objects have climbed from ~74 to ~112.

Call Count
  1acd2a38(Org.ACME.WileE.CoyoteBannerModel)-> 112
  152e0d70(Org.ACME.ApplicationObjects.User)-> 112
00db9010(Org.ACME.RocketSledDesktop.RocketSledDesktopWIndow)-> 111
00dd4cb8(Org.ACME.WileE.Views.Authentication.AuthenticationView)-> 111
1ac2df70(Org.ACME.WileE.CoyoteWorkspaceHost)-> 111
  00dc2e0c(Org.ACME.RocketSledShell.RocketSledShellView)-> 111
  152e4868(Org.ACME.CoyoteManagement.CoyoteModel)-> 104
1ac2afcc(Org.ACME.WileE.CoyoteWorkspace)-> 93
1ac2b024(Org.ACME.WileE.ComponentUtilizationServiceClient)-> 86
1ae04444(System.Collections.Generic.Dictionary`2[[Org.ACME.WileE.CompositeView.JWPanel, Org.ACME.WileE.CompositeView],[System.Int32, mscorlib]])-> 25
1adc4928(Org.ACME.WileE.CompositeView.JWPanelHost2)-> 25
1ae06130(System.Collections.Generic.Dictionary`2+Entry[[Org.ACME.WileE.CompositeView.JWPanel, Org.ACME.WileE.CompositeView],[System.Int32, mscorlib]][])-> 25
1abdaba8(Org.ACME.WileE.CompositeView.JWPanel2)-> 25
00f6e494(Org.ACME.ApplicationObjects.Session)-> 24
  1af92194(System.Collections.ObjectModel.ObservableCollection`1[[Org.ACME.Vitalsigns.Models.VitalSignsRecord, Org.ACME.Vitalsigns]])-> 11
1adc56c0(Org.ACME.WileE.WorkspaceBase+GetPanelCountEventHandler)-> 7

ObjSize

0:035> !objsize 1acd2a38
sizeof(1acd2a38) =     33590192 (   0x2008bb0) bytes (Org.ACME.WileE.CoyoteBannerModel)

0:035> !objsize 152e0d70
sizeof(152e0d70) =     33590192 (   0x2008bb0) bytes (Org.ACME.ApplicationObjects.User)

0:035> !objsize 00dc2e0c
sizeof(00dc2e0c) =     33590192 (   0x2008bb0) bytes (Org.ACME.RocketSledShell.RocketSledShellView)

Observation

We go back and look at the raw output of the reference chain to System.Byte[] and find the most commonly occurring Org.ACME objects and determine that the closest reference to System.Byte[] in an ACME object is usually Org.ACME.CoyoteManagement.CoyoteModel, which we believe could be the object that is being held in memory causing the memory usage. Also, on the top of the chain is what appears to be a timer event, System.Windows.Media.Animation.TimeManager, not a direct call from an explicit user action. We recommend that development look at the reference chain below and determine in the source code where Org.ACME.CoyoteManagement.CoyoteModel is being created and disposed and inspect it to make sure it is being properly disposed. Here is the above mentioned reference chain.

Common Reference Chain to System.Byte[]

ebx:Root:  00dc5d50(System.Windows.Media.Animation.TimeManager)->
  00dc5784(System.Windows.Media.MediaContext)->
  00dc591c(System.Collections.Generic.Dictionary`2[[System.Windows.Media.ICompositionTarget, PresentationCore],[System.Object, mscorlib]])->
  00ea9468(System.Collections.Generic.Dictionary`2+Entry[[System.Windows.Media.ICompositionTarget, PresentationCore],[System.Object, mscorlib]][])->
  00ea91f4(System.Windows.Interop.HwndTarget)->
  00db9010(Org.ACME.RocketSledDesktop.RocketSledDesktopWIndow)->
  00dc2e0c(Org.ACME.RocketSledShell.RocketSledShellView)->
  00dd4cb8(Org.ACME.WileE.Views.Authentication.AuthenticationView)->
  00ea652c(System.Windows.Controls.TextBlock)->
  00ea63b0(System.Windows.Controls.StackPanel)->
  00e61288(System.Windows.Controls.StackPanel)->
  00e62944(System.Windows.Controls.UIElementCollection)->
  00e62958(System.Windows.Media.VisualCollection)->
  00ea64b8(System.Object[])->
  00ea11f0(System.Windows.Controls.StackPanel)->
  00ea1498(System.Windows.Controls.UIElementCollection)->
  00ea14ac(System.Windows.Media.VisualCollection)->
  00ea3710(System.Object[])->
  00ea15d4(System.Windows.Controls.Image)->
  01619384(System.Windows.EffectiveValueEntry[])->
  0100910c(System.Windows.Automation.Peers.ImageAutomationPeer)->
  01008b00(System.Windows.Automation.Peers.UserControlAutomationPeer)->
  01008a90(System.Windows.Automation.Peers.UserControlAutomationPeer)->
  1cdec464(System.Collections.Generic.List`1[[System.Windows.Automation.Peers.AutomationPeer, PresentationCore]])->
  1cdec47c(System.Object[])->
  155e5b08(System.Windows.Automation.Peers.UserControlAutomationPeer)->
  1cdecf28(System.Collections.Generic.List`1[[System.Windows.Automation.Peers.AutomationPeer, PresentationCore]])->
  1cdecf60(System.Object[])->
  1b062404(System.Windows.Automation.Peers.UserControlAutomationPeer)->
  1ac2df70(Org.ACME.WileE.CoyoteWorkspaceHost)->
  1ac2afcc(Org.ACME.WileE.CoyoteWorkspace)->
  1ac2b024(Org.ACME.WileE.ComponentUtilizationServiceClient)->
  152e0d70(Org.ACME.ApplicationObjects.User)->
  1adc5878(System.ComponentModel.PropertyChangedEventHandler)->
  1adc5860(System.Object[])->
  1adc5840(System.ComponentModel.PropertyChangedEventHandler)->
  1acd2a38(Org.ACME.WileE.CoyoteBannerModel)->
  152e4868(Org.ACME.CoyoteManagement.CoyoteModel)->
  1b513c40(System.ComponentModel.PropertyChangedEventHandler)->
  1b513c28(System.Object[])->
  1b513c08(System.ComponentModel.PropertyChangedEventHandler)->
  1b513bd8(MRPQL.MRPQLViewModel)->
  1b7aa524(MRPQL.MRPQLViewModel+ReadyEventHander)->
  1b513a38(MRPQL.MRPQLWindow)->
  1b528f64(System.Windows.Controls.Primitives.ToggleButton)->
  1b52ced0(System.Windows.EffectiveValueEntry[])->
  1b7a2320(System.Windows.ModifiedValue)->
  1b52ce54(System.Windows.Data.BindingExpression)->
  00dca6a8(MS.Internal.Data.DataBindEngine)->
  017ee558(System.Windows.Controls.ContentControl)->
  01ba64b8(System.Windows.EffectiveValueEntry[])->
  017ef238(System.Windows.DataTemplate)->
  017ef73c(System.Windows.TemplateContent)->
  017ef764(System.Windows.TemplateLoadData)->
  017ef7ec(System.Windows.TemplateContent+ServiceProviderWrapper)->
  017ef390(MS.Internal.Xaml.ServiceProviderContext)->
  017ef128(MS.Internal.Xaml.Context.ObjectWriterContext)->
  017ef164(MS.Internal.Xaml.Context.XamlContextStack`1[[MS.Internal.Xaml.Context.ObjectWriterFrame, System.Xaml]])->
  017ef1b8(MS.Internal.Xaml.Context.ObjectWriterFrame)->
  0170deb4(MS.Internal.Xaml.Context.ObjectWriterFrame)->
  0170def4(MS.Internal.Xaml.Context.ObjectWriterFrame)->
  01437a6c(System.Windows.ResourceDictionary)->
  01437b94(System.Windows.ResourceDictionaryCollection)->
  01437bc0(System.Collections.Generic.List`1[[System.Windows.ResourceDictionary, PresentationFramework]])->
  016ae63c(System.Object[])->
  016cb3bc(System.Windows.ResourceDictionary)->
  016cdb4c(System.Windows.ResourceDictionaryCollection)->
  016cdb78(System.Collections.Generic.List`1[[System.Windows.ResourceDictionary, PresentationFramework]])->
  016cdccc(System.Object[])->
  016dcbd8(System.Windows.ResourceDictionary)->
  016f42f4(System.Windows.Baml2006.Baml2006Reader)->
  016f4544(System.Windows.Baml2006.BamlBinaryReader)->
  016f44fc(System.Windows.Baml2006.SharedStream)->
  016f4080(System.IO.MemoryStream)->
  027660c8(System.Byte[])


 

By Jon Fowler, Sr Performance Engineer at Orasi Software

Performance development and test.

Leave a comment