Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Reducing WinForm Memory Footprint with SetWorkingSet


:P
On this page:

Windows Forms apps are pretty bloated in terms of memory usage. The main reason .Net apps have such a huge footprint is that the JIT compiler loads when the app starts and all that bootstrap code and a ton of the WinForms engine is loaded and compiled at startup and gets loaded into your process. Beside the fact that this takes up processor cycles it also consumes a lot of memory. The JIT is pretty good about which code gets compiled – for the most part it compiles only code that actually gets run, but the framework itself pulls in a lot of code as well and that gets compiled as well. Third party controls - ditto. The result of this is that on startup your app consumes a lot of resources that you will not need any longer once the app is up and running. Actually if you access another new part of the application that part will compile later, but for many apps the startup and main application form make up a huge chunk of what gets loaded and compiled as the data engine and business objects etc. usually are among the things that get called at startup. A large percentage generally gets compiled right at startup.

 

If you’ve ever run your app and looked at Task Manager you might have noticed that the app starts out with a significant amount of memory. A basic WinForm app with a couple of textboxes and a button typically will run around 8 megs. If you move the form around a bit closer to 10. You then can minimize the app and it generally reduces to some really low memory usage number which slowly creeps back up as you open the form back up. What’s happening is that the app internally is adjusting the Working Set for the application which aggressively reduces the memory in use by the app. The app will reclaim what it needs, but for that moment the memory usage goes down drastically and it will stay much lower than the original startup usage.

 

For .Net applications this is a useful feature because there’s so much gunk that loads in .Net apps that goes away. You can force your app to minimize and pop back up to get the same effect, but this is probably not something that you want to do in your application <g>. A better way is to adjust the working set in your applications like this:

 

public static void SetWorkingSet(int lnMaxSize,int lnMinSize)

{

      System.Diagnostics.Process loProcess =       System.Diagnostics.Process.GetCurrentProcess();

      loProcess.MaxWorkingSet = (IntPtr) lnMaxSize;

      loProcess.MinWorkingSet = (IntPtr) lnMinSize;

      //long lnValue = loProcess.WorkingSet; // see what the actual value

}

 

I’ve taken to calling this static method function in my code at the end of the Win form’s Load event and also in the Deactivate event. The latter is kind of cheating . If you go checking to task manager for memory usage you’re actually deactivating the app, and so you get a lower value.

 

private void frmWebStoreMain_Deactivate(object sender, System.EventArgs e)

{

      wwUIRoutines.SetWorkingSet(750000,300000);

}

 

The value will not actually reduce to exactly what you tell it to, but Windows will try to reduce as much as possible. Memory usage readings in TaskManager aren’t really all that accurate, but I’ve heard from several people using some of our tools that they really were surprised by the memory usage. Doing something like the above reduced memory usage considerably.

 

For example, West Wind Web Monitor without the above code runs around 14-15megs. With the above code (as part of the monitoring thread) the typical memory usage runs between 5-7 megs. For the West Wind Web Store Client app without the above the app runs 25 megs. With the code it runs at 7-10megs.

 

 

In a way this is cheating the app – but it certainly improves the impression of memory usage of the application on the machine. I suspect that this has little effect on actual performance as the memory would be reclaimable anyway if the system needed it. But given that some people look at program size as an indication of the bloat in an app it can’t hurt to do this.

 

Note that there is some overhead in doing this. You’re freeing causing memory to be freed from the app – memory that will have to be reclaimed later if it is needed again. So be careful with this sort of thing in high performance applications.

 

 


The Voices of Reason


 

Dan
February 19, 2004

# re: Reducing WinForm Memory Footprint with SetWorkingSet

Thanks for this article- your method keeps the boss happy!

M. Griffie
October 20, 2004

# re: Reducing WinForm Memory Footprint with SetWorkingSet

I used this technique for an incredibly simple app I was making, it sure shut my friend up about how much memory usage was showing in taskmanager ;)

Smitha
November 17, 2004

# re: Reducing WinForm Memory Footprint with SetWorkingSet

This method is usefull some times, but for some application, this may raises the memory insufficient exception. I that case this fuction is not usefull.

Rick Strahl
November 18, 2004

# re: Reducing WinForm Memory Footprint with SetWorkingSet

Smitha, you need to play with the value and set it at a level that isn't too low. It's pretty easy to find that spot though by setting the value fairly low and observing where memory goes when the app minimizes. That's the level you want to set it to.

Remember that this is not something that really doesn't help drastically with memory usage - it's a hack at best and mainly for applications to 'look' more palatable when they are not active in Task manager. The actual memory usage (private bytes) may actually be higher or lower that what you see in the Working Set.

Romy
December 02, 2004

# re: Reducing WinForm Memory Footprint with SetWorkingSet

Thanks man for this article - your method solved a big problem

Romy
December 02, 2004

# re: Reducing WinForm Memory Footprint with SetWorkingSet

More safe, try like that:

public abstract class SettingsProc
{
static bool m_TipAction;
static SettingsProc()
{
m_TipAction = true;
}
public static void SetWorkingSet()
{
System.Diagnostics.Process loProcess = System.Diagnostics.Process.GetCurrentProcess();
if(m_TipAction == true)
{
loProcess.MaxWorkingSet = (IntPtr)((int)loProcess.MaxWorkingSet - 1);
loProcess.MinWorkingSet = (IntPtr)((int)loProcess.MinWorkingSet - 1);
}
else
{
loProcess.MaxWorkingSet = (IntPtr)((int)loProcess.MaxWorkingSet + 1);
loProcess.MinWorkingSet = (IntPtr)((int)loProcess.MinWorkingSet + 1);
}
m_TipAction = !m_TipAction;
}
}

//.............
private void frmWebStoreMain_Deactivate(object sender, System.EventArgs e)

{

wwUIRoutines.SetWorkingSet();

}

Best regards

Rick Strahl
January 06, 2005

# re: Reducing WinForm Memory Footprint with SetWorkingSet

One important note: The above requires Admin privileges. So it's important to trap exceptions in case you're running without admin rights.

extra bits that didn't fit
February 01, 2005

# Fat and PasteOff?


ragincougar
February 10, 2005

# re: installed w/o admin rights any workaround

Hi all,
I installed this app on a machine where i dnt have the admin rights.I keep getting exceptions when ever i try to run the app.Is there a way to work around w/o changing any code and make it work.
Any response is appreciated.

Rick Strahl
February 10, 2005

# re: Reducing WinForm Memory Footprint with SetWorkingSet

Put the code that reduces the working set into a try/catch block. This will catch the exceptions at least in scenarios where the necessary rights aren't available and work fully where they are.

Peter Vogel
June 22, 2005

# re: Reducing WinForm Memory Footprint with SetWorkingSet

It turns out that it doesn't matter what you set maxWorkingSet to--setting it to any value apparently causes the working set to be re-evaluated and excess discarded. So this code seems to accomplishes the same goal:

loProcess.maxWorkingSet = loProcess.maxWorkingSet

haha
September 09, 2005

# re: Reducing WinForm Memory Footprint with SetWorkingSet

This solution is hilarious. Works great even though it doesnt really do anything. But since task manager is what everyone uses to see how much memory is being used, this hack works awesome. Everyone will think your application is expertly coded and efficient!

Pete Chalker
September 10, 2005

# re: Reducing WinForm Memory Footprint with SetWorkingSet

Is there not anyway to get around the admin privileges issue?

Additionally MSDN documentation for the same does not mention anything like. It mentions of SecurityPermission level - Permission.Unrestricted.

Is there possibly a way to use this to facilitate the same for users without admin privileges?

A quick response will be much appreciated.

Troub
January 16, 2006

# re: Reducing WinForm Memory Footprint with SetWorkingSet

OH MAN THANKS!!!!! this is WAY COOL
Just converted the code to VB.NET and it works GREAT!!!

Couple of notes on the conversion
Here's a VB.NET call notice the system.IntPtr conversion to make it work

SetWorkingSet(System.IntPtr.op_Explicit(CInt(750000)), System.IntPtr.op_Explicit(CInt(300000)))

Public Sub SetWorkingSet(ByVal lnMaxSize As System.IntPtr, ByVal lnMinSize As System.IntPtr)

Try
Dim loProcess As _ System.Diagnostics.Process_
= System.Diagnostics.Process._
GetCurrentProcess()

loProcess.MaxWorkingSet = lnMaxSize
loProcess.MinWorkingSet = lnMinSize

Catch
'do nothing. this only works on a machine_ onwhich the user has admin rights
End Try
END SUB

Mark
March 05, 2006

# re: Reducing WinForm Memory Footprint with SetWorkingSet

This made me laugh out loud. I have been using this little cheat in my MFC C++ applications for years now, to great effect. Hey, perception is everything... remember?!?! :-)

It was nice to see the same concept applied to WinForms apps, which tend to bloat up the working set very quickly.

Thanks for the tip!

# память приложения

память приложения Объясните ситуацию пожалуйста.Есть приложение FinForms.Посмотрел сколько приложение занимает в оперативной памяти и вот что заметил. Когда окно развернуто на экране, приложение занимает 5МБ, нажимаю свернуть, тут же размер умень

Scott Golightly's Blog
November 09, 2006

# Scott Golightly's Blog - Hack to reduce the working set of Windows Forms applications


Rizwan Khalid
November 27, 2006

# re: Reducing WinForm Memory Footprint with SetWorkingSet

hi

i just implemented this solution but the problem is some times i got error "The parameter is incorrect" while setting MaxWorkingSet.....
this is very random.... and i only managed to reproduce it only once but still not been able to understand the cause.....

this is what i get....
at System.Diagnostics.Process.SetWorkingSetLimits(Object newMin, Object newMax)
at System.Diagnostics.Process.set_MaxWorkingSet(IntPtr value)
at MemoryOptimizer.SetWorkingSet()

any ideas???

# память приложения

память приложения &lt;P&gt;Все правильно, когда вы сворачиваете форму, .NET для экономии ресурсов вызывает функцию SetProcessWorkingSetSize c параметрами -1 для максимального и минимального working set size. На самом деле вся эта память переходит из

Scott Golightly's Blog
January 20, 2007

# Scott Golightly's Blog - Friday, 03 February 2006


Ray Levi
February 06, 2007

# re: Reducing WinForm Memory Footprint with SetWorkingSet

This isn't supported in the 2.0 framework. Does anyone have a similar method for 2.0?

Omar Fawzi
June 13, 2007

# re: Reducing WinForm Memory Footprint with SetWorkingSet

Thanks Mr.Rick Strahl, your articles allow me to know more about improving performance to DotNet Application.

Rick
December 05, 2007

# re: Reducing WinForm Memory Footprint with SetWorkingSet

Obviously you don't understand garbage collection in dot net, the general rule of thumb is don't keep anything around in memory any longer than you absolutely have to, the reason is at anytime, that is unbeknownst to the developer, the CLR runs out of pre-allocated memory and it triggers a garbage collection. This is never consistent or predictable, when garbage collection happens ANYTHING that is reference or allocated gets promoted to the next "generation", in general the older an object or allocation is the longer it tends to hang around before it is completely released and re-used by the CLR. By setting the working set to an arbitrary number you are just triggering garbage collections sooner, which will cause your app to spend more time collecting garbage rather than doing its work. The ultimate goal of the CLR and it's garbage collection algorithms is to find an optimal working set were your code doesn't allocate more memory than it actually needs, or is constantly asking the OS for more memory only to release it again moments later.

Take a look at the SciTech memory profiler and watch the tutorials.

You will then understand better why certain apps seem to grab a lot of memory. There are a lot of articles around the internet that describe how to write efficient dot net code.

After that there are a lot of articles posted around the internet describing the details of garbage collection.

.Net is a very powerful, productive and capable system, allowing mere mortals to build impressive systems, on the other hand, unfortunately there are a lot of developers out there that aren't taking the time to really understand how it works internally, and this is causing mis-conceptions that dot net is a memory pig. It's not dot net, it's the way the application is written that prevents garbage collection, translating into larger and larger working sets.

iMap
December 11, 2008

# re: Reducing WinForm Memory Footprint with SetWorkingSet

Hi,

Ok with your analyse but:
How to reduce memory allocation with DataTable when MaDataTable.dispose() doesn't have effect...

(escuse for my english..)

Nathan
February 03, 2009

# re: Reducing WinForm Memory Footprint with SetWorkingSet

Rick said: "there are a lot of developers out there that aren't taking the time to really understand how it works internally".

I know very well that from a developer's standpoint, the memory is released if needed by other applications. However, also as a developer, I need to make my users happy. And to them, they are only happy if the .NET application doesn't "appear" to use up that much memory. I don't care if it takes a a few more miliseconds of CPU time to re-evaluate the working set, it makes my users happy.

And as far as Garbage Collection goes, forcing Garbage Collection does not have the same affect. I have tried it as well, and though GC.Collect() forces garbage collection to occur, it does not release any memory from the working set, and therefore does not appear to release much memory at all.

Ravikiran
March 16, 2009

# re: Reducing WinForm Memory Footprint with SetWorkingSet

Thank u very Much.....
Your Article help me a lot.....keep rocking.....

koma
August 27, 2009

# re: Reducing WinForm Memory Footprint with SetWorkingSet

what is mean the values which sent (750000 and 3000)

Nasa
October 08, 2009

# re: Reducing WinForm Memory Footprint with SetWorkingSet

Thanks a lot for your wonderful article!, it really helped me lot!

ALiNSC
June 27, 2010

# re: Reducing WinForm Memory Footprint with SetWorkingSet

how to reduce or control the virtual memory ?

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024