Posts .NET Application Memory Flush via Interop - Revisited
Post
Cancel

.NET Application Memory Flush via Interop - Revisited

As I've stated before, I do make mistakes ;-)

I have an application that I've written for my employer that appears, under certain *unidentified* circumstances to have a very slow memory leak.  While trying to narrow down where it could be, I pulled one of my components out to test it with a console interface as a harness (to reduce the amount of outside memory being used) and leveraging the CLR Profiler (free) and the .NET Memory Profiler (14 day eval) to see what is happening.  One of the things making this difficult, since I'm trying to look at native memory as well, is the effect that the framework has on the application and Windows reporting memory consumption.  So I decided to add the memory flush method that I posted back in November 2003 to the mix.  Even though I had several warnings around that code posting, there was one that wasn't stated.  Although it does do what is says, on the surface, there is a slight bloating effect inherent to it as well.  In addition, it's seriously overkill since it's forcing a garbage collection.  Here is an updated code listing:

<FONT color=#0000ff>Public Class MemoryManagement
 
  <FONT color=#0000ff>Private</FONT> <FONT color=#0000ff>Declare</FONT> <FONT color=#0000ff>Function</FONT> SetProcessWorkingSetSize <FONT color=#0000ff>Lib</FONT> "kernel32.dll" ( _
    <FONT color=#0000ff>ByVal</FONT> process <FONT color=#0000ff>As</FONT> IntPtr, _
    <FONT color=#0000ff>ByVal</FONT> minimumWorkingSetSize <FONT color=#0000ff>As</FONT> <FONT color=#0000ff>Integer</FONT>, _
    <FONT color=#0000ff>ByVal</FONT> maximumWorkingSetSize <FONT color=#0000ff>As</FONT> <FONT color=#0000ff>Integer</FONT>) <FONT color=#0000ff>As</FONT> </FONT><FONT color=#0000ff>Integer

 
<FONT color=#0000ff>Public</FONT> <FONT color=#0000ff>Shared</FONT> <FONT color=#0000ff>Sub</FONT> FlushMemory()
<FONT color=#008000>    'GC.Collect()
    'GC.WaitForPendingFinalizers()
</FONT>    <FONT color=#0000ff>If</FONT> (Environment.OSVersion.Platform = PlatformID.Win32NT) </FONT><FONT color=#0000ff>Then
      Dim <FONT color=#000000>p
As </FONT><FONT color=#000000>Process = Process.GetCurrentProcess</FONT></FONT><FONT color=#0000ff>
     
SetProcessWorkingSetSize(p.Handle, -1, -1)
      p.Dispose
    <FONT color=#0000ff>End</FONT> </FONT><FONT color=#0000ff>If
 
<FONT color=#0000ff>End</FONT> </FONT><FONT color=#0000ff>Sub

End
<FONT color=#0000ff>Class</FONT></FONT>

The problem with the previous version is that the GetCurrentProcess was creating a reference to a Process that was staying in memory until it's finalizers would run during a GC0 (Garbage Collection level 0).  By adding in the Dispose, you are removing the bloat by specifically telling the framework to release (what appears to be) the un-managed reference to a Process.  Again, this wasn't that big of a deal since we are talking about a relatively small amount of memory, but still... it was wrong... now it's right ;-)

As for forcing the GC, I don't really think that it is necessary in order to get Windows to see the “true” memory consumption as described in the previous article.  Also, it's just not good .NET practice to do so... so it's been removed. 

Also, due to these modifications, the warnings in the previous article are no longer relevant... since we aren't forcing a GC.  The only warning now is the fact that you are using P/Invoke and have to adhere to whatever restrictions doing so incur.

This post is licensed under CC BY 4.0 by the author.