Simulate a window minimize / memory release in your .NET apps

Once in a while you have people complaining in the forums that their .NET applications are not releasing memory but that if they minimize the app and restore it, then the memory usage goes down. Why this happens is explained in this Microsoft KB article :

You can simulate this in your code too (under extreme conditions when you really need the memory). In my case I had to do this in an app that loaded very large PNG files – once in a while we’d get a memory exception and then I’d call this method and retry and it would work. It does sound a bit hack-ish but there was nothing else we could do.

[DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize",
  ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
private static extern int SetProcessWorkingSetSize(
  IntPtr process, int minimumWorkingSetSize, int maximumWorkingSetSize);

public static void ReleaseUnusedMemory()
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
    SetProcessWorkingSetSize(
        System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
}

I thought it’d be nice to post this here in case anyone else ever needs this.

Advertisements

3 thoughts on “Simulate a window minimize / memory release in your .NET apps

  1. I used it to my application. When I load a some thing to a grid, and call your method, the memory goes down, but when I load another record, the memory goes up quickly with doubled size. It seems like it accumulated the records I loaded at first time. Any idea about this issue? thanks.

  2. In response to Danny ^[

    This is essentially how the system trims the process when its top-level window is minimized. This does not mean that the memory pages used by the process are immediately discarded from RAM. In fact, these pages may remain resident for quite a while. They are simply flagged so that the system can use them for other processes as necessary. This is significantly faster than waiting on the system’s standard trimming algorithm. ]

  3. Repeat after me: memory that is not in use is wasted. Memory that is not in use is wasted…

    GC will clean up what it is necessary to clean up. If you try to allocate more memory than your process address space has available, that immediately invokes GC to try to find more space. GC doesn’t give up because it’s taking too long: if there is space to be had, it will find it.

    An object that is no longer referenced might not be deallocated on the first GC if it requires finalization. Finalization is a bit of a mess – the first GC pushes the object onto a queue of objects requiring finalization, then only once its finalizer has run is it then eligible to be deallocated. This generally causes such objects to last a lot longer (as the older generations, which it will now be in, are collected less frequently).

    In addition, if you have handed out a pointer to an object to native code, it will be pinned, meaning it can’t be moved, which fragments memory. Normally GC compacts memory causing more free space.

    What does this mean? Always, always call Dispose. That destroys any links into (for example) GDI which might be pinning the object, and ensures that the finalizer doesn’t have to run. There are many classes with finalizers that you might not expect, simply because they derive from some common base class (System.ComponentModel.Component, for example).

    I suspect your problem was that your images required finalization, and was actually solved by calling Collect and WaitForPendingFinalizers, rather than asking Windows to trim the working set.

    Trimming the working set doesn’t actually reduce the amount of memory available as Windows counts each process’s private memory allocations, not their working sets, against the sum of physical memory and page file. In XP’s Task Manager, this is shown as Commit Charge. All that happens, as others have said, is that the physical memory pages end up on the modified and standby lists. Windows XP double-counts these, in both the ‘Available’ and ‘System Cache’ sections of Task Manager. Windows only keeps a small buffer of zeroed pages available – dumping more pages on the standby list doesn’t affect this.

    Let Windows manage the memory.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s