+1.916.577.1977 | Downloads | Buy | Register | Login
 Search  
Tuesday, July 08, 2008
Search Blogs
 

Available Blogs
 

Previous Blogs
 

Technorati
 
More blogs about coversant.

About Coversant
 

FakeOutTheUserToThinkWeDontUseAnyMemory
 
Location: BlogsStarin' at the Wall    
Posted by: JD Conley 5/8/2006 3:28 PM

There comes a time in every project where the developers realize we are building software for the users, rather than for ourselves. A user's perception can be the difference between a good and a bad reference, and we all know how detrimental bad word of mouth can be. This unfortunate reality hit me square in the face recently when I was told by a customer that "your application is bloatware".

Any desktop application with a user interface, written in .NET, that does anything interesting, can easily be mistaken for bloatware. It's quite easy to create a super elegant application with no memory leaks that appears to use 50MB or more of memory. I say appears, because the figure everyone sees in Task Manager is the "Working Set" size. Users (myself included, up until recently) see large working set sizes as a sign of bloatware and poor programming.

This is simply not the case. The working set is more along the lines of the amount of physical memory the OS thinks your application might need or needed at one point, including shared memory and all sorts of other complicated things that .NET developers aren't supposed to have to think about. If your system was in need of physical memory for other processes much of this perceived bloat would either be reclaimed and put to better use, or paged out to disk.

At the end of the day, the reality of the situation doesn't matter. Your users think your application is bloated. What do you do? Well, you FakeOutTheUserToThinkWeDontUseAnyMemory.

using System.Diagnostics;

namespace Coversant.Utility {
    public static class MemoryUtility
    {
        private static volatile bool _enabled = true;

        public static void FakeOutTheUserToThinkWeDontUseAnyMemory()
        {
            if (!_enabled)
                return;

            try
            {
                Process curProc = Process.GetCurrentProcess();
                curProc.MaxWorkingSet = curProc.MaxWorkingSet;
            }
            catch
            {
                //Some users won't have permission to adjust their working set.
                _enabled = false;
            }
        }
    }
}

Yep, that's it. Call that method (.NET 2.0 only -- in 1.x you had to P/Invoke) and watch the magic happen. In our applications we set it up on a timer that runs every 30 seconds and after any events we know will raise the working set, usually after loading new assemblies or after a window is closed . Running this code causes Windows to free up as much of the working set as possible. Usually this sends most of your bloat to the page file where it will remain forever. In our case, the application had a 50MB working set and really only needed about 10MB of physical memory after it was running. There is, however, one big gotcha. An application can only attempt to adjust its working set if it is running with appropriate permissions (typically a local Administrator).

Yes, your users perceptions are reality. Using this trick/hack helps keep reality in line.

Permalink |  Trackback

Comments (11)  
Re: FakeOutTheUserToThinkWeDontUseAnyMemory    By pankaj on 6/15/2006 11:46 AM
This is interesting. I've been writing c# applications since the past one year now, and everytime I write one and give it to the non-developers for testing and shipping to customers, they have always had some negative feedback on the number of threads and the memory utilization of my app.
This will certainly help to keep the "reality" in check.

Re: FakeOutTheUserToThinkWeDontUseAnyMemory    By Greg Young on 7/24/2006 4:55 PM
Couldn't asking them to minimize your app (which will reduce the working set go a long way towards showing them the truth)?

Re: FakeOutTheUserToThinkWeDontUseAnyMemory    By jconley on 7/28/2006 2:52 PM
Yes, you could ask them to minimize their app. Unfortunately most users won't talk to you in the first place, at least in the product/consumer world. In an enterprise I don't think this would be as big of an issue.

Re: FakeOutTheUserToThinkWeDontUseAnyMemory    By Tom on 9/25/2006 10:00 AM
Wow, nice work.
I know this doesnt solve a thing, but it sure looks far more user-friendly. (I'm doing a background app, which should not look like memory hogs ;) )

Re: FakeOutTheUserToThinkWeDontUseAnyMemory    By john on 1/2/2007 11:01 AM
This is a very smart idea. I am confused with the memory usage of .Net application displayed by the task manager sometimes, this is definitely helpful.

Re: FakeOutTheUserToThinkWeDontUseAnyMemory    By Ted on 2/21/2007 4:31 PM
So what you're proposing is that people (including yourself) deceive their customers/users and on top of that, they run their computers as administrator (if I understand that part of it correctly)? This is neither secure (again, if I understand that part correctly) or smart. I'll bet more users/customers will be lost when they find out that they've been deceived. I'd prefer my software to "be bloatware" than to lie to me.

Cool trick , non the less and please don't take my comments as an argument, but what I wrote is actually the way it appears to me. Please correct me if I'm wrong.

Re: FakeOutTheUserToThinkWeDontUseAnyMemory    By jconley on 2/21/2007 4:38 PM
Ted - We are not doing anything Windows and .NET wouldn't do anyway. We're just making it happen sooner than usual. Typically the working set size (the figure shown in task manager) will only shrink in .NET apps when Windows is getting close to running out of memory or you allocate and deallocate a lot of memory. All this trick does is coax the working set size to shrink to the amount of physical memory that is actually needed by the process at that time. Usually it usually just sends a bunch of stuff out to the page file that isn't needed in memory any more.

Also, the part about being an administrator is not a security issue. It's just that this trick only works when the user context running the .NET app domain is an administrator. Otherwise it has no effect. Experience has shown that the only users that even look at task manager and care about memory usage are running Windows as administrators, though.

Re: FakeOutTheUserToThinkWeDontUseAnyMemory    By Sandeep Thoppil on 6/22/2007 9:47 AM
I added the code to my Win App's MDI Activate, Wow looks like an awesome Garbage collection happening. After some work is done and the user closes the child window MDI gets activated, our code works there...the memory allocated for that child window is released...altogether a great Drama.

Re: FakeOutTheUserToThinkWeDontUseAnyMemory    By Leon Anderson on 6/22/2007 9:47 AM
I am very interested in how this works, as the .NET framework sems to do too much stuff for you (as frontpage generates too much html code for you )...I was wondering if you could start the process as a different user or seperate thread to counter the person not having admin privs on his machine.

new code for all guys    By Leon Anderson on 6/22/2007 9:48 AM
I came up with some new code to be placed inside the main class being executed to allow for better use of this nice snippet even though not everyone has admin privs, this allows to have nice looking task manager if the user is idle on your app


static void Main()
{
Application.EnableVisualStyles();
ApplicationEventHandlerClass AppEvents = new ApplicationEventHandlerClass();
Application.Idle += new EventHandler(AppEvents.OnIdle);
Application.Run(new CustomerProfile());
}
public class ApplicationEventHandlerClass
{
protected static volatile bool _enabled = true;
public void OnIdle(object sender, EventArgs e)
{
FakeOutTheUserToThinkWeDontUseAnyMemory();
}
public static void FakeOutTheUserToThinkWeDontUseAnyMemory()
{
if (!_enabled) return;
try
{
System.Diagnostics.Process curProc = System.Diagnostics.Process.GetCurrentProcess();
curProc.MaxWorkingSet = curProc.MaxWorkingSet;
}
catch { _enabled = false; }//some user dont have admin privs.
}
}

Re: FakeOutTheUserToThinkWeDontUseAnyMemory    By jconley on 6/22/2007 9:50 AM
Leon: I wouldn't recommend doing it in every tick of the Application.Idle event. This can happen many times per second and lead to poor performance of your application. Typically you want to do it in scenarios like Sandeep's where you know the user just performed an action that released a lot of memory.


©2008 Coversant, Inc. | Privacy Policy | About Coversant | Contact Info