Very large number of System.Weakreferences causing 'leak'?

Use this forum for questions on how to use .NET Memory Profiler and how to analyse memory usage.
Post Reply
Simon Lockington
Posts: 5
Joined: Mon Jul 10, 2006 4:31 am

Very large number of System.Weakreferences causing 'leak'?

Post by Simon Lockington » Wed Dec 12, 2007 5:39 am

Hi there, I'm hoping you can help me.
I've been using MemProfiler 3.0 for quite some time now to 'tidy up' a Windows Service application I'm writing. However I need a little help to fix the last remaining problem.

Each time I collect the heap, I have a large number of system.weakreferences which only ever increase with time. After an hour or so of running, I have 3.5mb total bytes allocated to this which corresponds to the increased memory usage of my application over time.

When looking at a number of these instances, they seem to have been created in either webservice calls, or calls to table adapters in a dataset (VB.NET 2.0).

All calls to both the webservices and the table adapters are contained within using statements.

I'm not sure what else I can do to ensure these instances are disposed and removed correctly?

I've tried to do a lot of research on what the system.weakreference object is on the net but come away more confused. I can only assume it is being used by the underlying Framework code and not any I have written myself. However, I can't continue to allow the application's memory usage to continue to grow in size like it does.

Any ideas would be greatly appreciated.

Thanks,
Simon

Andreas Suurkuusk
Posts: 1029
Joined: Wed Mar 02, 2005 7:53 pm

Post by Andreas Suurkuusk » Wed Dec 12, 2007 9:35 pm

A WeakReference is used to keep a reference to a managed instance, without preventing it from being garbage collected. If the instance that the WeakReference references is garbage collected, the "Target" of the WeakReference will be null. At this point, the WeakReference should preferably not be used anymore. All references to the WeakReference instance should be removed. If this is not performed, the WeakReference instance will be kept in memory.

I assume that you have a lot of WeakReferences in your service that are no longer referencing any other instances. In order to find out why the WeakReference instances are not garbage collected, you should investigate the root paths of the instances. You can do this either in the Type details view (where the shortest root paths will be combined) or in the Instance details view (where you will see all root paths for a specific WeakReference instance). If you need more help with investigating this issue, you can post the allocation call stack and one more root paths of the WeakReference instance to this thread. Hopefully I will be able to give you some additional information about why the WeakReference is not GCed.
Best regards,

Andreas Suurkuusk
SciTech Software AB

Simon Lockington
Posts: 5
Joined: Mon Jul 10, 2006 4:31 am

Post by Simon Lockington » Thu Dec 13, 2007 9:57 am

Thanks very much for your reply Andreas, I really appreciate it.

This problem seems to be the only one I can find with the app now. There are a huge amount of weakreferences generated (1,253 in two minutes).

Looking at a large selection of instances, they seem to have been allocated during the constructor of the WebService object (AutomationService) or a call to one of the table adapters in the OLEDB 2 data access layer.

Do the screen shots help at all?

All Webservice and data access code is contained withing Using Statements which should manage this shouldn't they?

Image
Image

Andreas Suurkuusk
Posts: 1029
Joined: Wed Mar 02, 2005 7:53 pm

Post by Andreas Suurkuusk » Thu Dec 13, 2007 3:15 pm

I assume that the screenshots are from the Type details of the WeakReference type and from the Instance details of a WeakReference instance. Is that correct?

The call stack in the first screenshot shows that the WeakReference is created in the AutomationService constructor. Have you investigated this constructor and seen how the WeakReference is created and used?

The root path shows that the WeakReference has been stored in an ArrayList referenced from the static field __ENCList. This list needs to be periodically purged from left-over WeakReferences (i.e. WeakReferences whose Target is null). The using statement makes sure that the Dispose method is called on disposable instances, but unless the Dispose method performs cleanup of the __ENCList ArrayList, this will not help with the issue you have.

I suggest that you take a look at the tblMatrixTableAdapter class, and try to add code that removes left-over WeakReferences from the __ENCList ArrayList.
Best regards,

Andreas Suurkuusk
SciTech Software AB

cd_mackenzie
Posts: 2
Joined: Mon Jun 23, 2008 6:05 pm

Post by cd_mackenzie » Mon Jun 23, 2008 6:06 pm

This memory leak is a known bug in the .NET frameworks. __ENCList is an internal .NET class that is used to provide Edit and Continue functionality. The only resolution to this issue is to recompile in Release mode. (Which is unfortunate if you had been using the debug mode to provide detailed exception reporting in production environments.)

http://support.microsoft.com/?kbid=919481

cd_mackenzie
Posts: 2
Joined: Mon Jun 23, 2008 6:05 pm

Post by cd_mackenzie » Tue Jun 24, 2008 1:43 pm

Something like the following may also work to clear out this memory; you probably will want to alter this so that it only works against your own specific assemblies. (Or only go against the executing assmebly, as comment out below, and eliminate the "GetAssemblies" for loop.)

Code: Select all


    Sub Cleanup__ENCList()
        If (Not System.Diagnostics.Debugger.IsAttached) ) Then
            Dim asm As Assembly '= Assembly.GetExecutingAssembly()
            For Each asm In AppDomain.CurrentDomain.GetAssemblies()
                For Each type As Type In asm.GetTypes()
                    Dim myFieldInfo As FieldInfo = type.GetField("__ENCList", BindingFlags.NonPublic Or BindingFlags.Static)
                    If Not myFieldInfo Is Nothing Then
                        Dim al As ArrayList = myFieldInfo.GetValue(Nothing)
                        al.Clear()
                    End If
                Next
            Next
        End If
    End Sub

Post Reply

Who is online

Users browsing this forum: No registered users and 29 guests