Introduction

If your computer is running hot or battery is running out quickly, then it is most likely due to some application or process consuming high CPU or memory. If you keep running applications for a long time, for example, Outlook, then it continues to grow in memory consumption and does not free up memory efficiently. As a result, your computer runs out of physical memory and other applications run slower. Sometimes Outlook, browser, image editing applications or some other applications start taking full CPU as they get into some infinite loop and make your CPU hot and you get sluggish performance from your application.

CPUAlert is an application that monitors CPU and memory consumption of applications and alerts you if some application is consistently taking high CPU or high memory. It will not only save your CPU and battery’s lifetime but also make your computer run smoothly and let your active applications run as fast as possible.

How to Use the Application

While it is running, if some process is consuming more than 200 MB memory, it will show you an alert:

Here you can see that my Outlook is taking 244 MB of physical RAM.

You can either postpone the alert for 5 mins (just press ESC), or ignore the process permanently so that you no longer receive alerts for the process anymore, or you can close it and reclaim memory.

The handy feature is “Restart” which closes the application and starts again. This generally frees up memory that clogs up the process.

The same alert will come up if some process is consuming more than 30% CPU for over 5 mins.

You can configure all these settings like what’s the tolerable limit for CPU and memory, how frequently to show the alert, how long to wait before closing an application, etc. by right clicking on the Task bar icon and choosing Settings.

The application registers itself to start at Windows startup. If you want to remove it from Windows Startup, just delete the application shortcut from Start Menu->All Programs->Startup menu.

Using the Code

CPU Alert is a small project. The important files are:

MonitorCPUForm.cs: This is the main window which is loaded when the app starts. It hides itself in the system tray and keeps the app running in background. It also hosts a "Settings" view which lets you change the CPU and Memory threshold, alert interval, etc. It also orchestrates the operations and shows the necessary alerts.

KillProcessForm.cs: It has just the UI for the alert that you see in the above popup. No intelligence.

Monitor.cs: This is the important class that does the monitoring, measurement of CPU and Memory usage and raises the alert. If you want to have this kind of feature in your application, you can reuse this class.

Let's look at the Monitor.cs class first which has the brainpower to monitor CPU and memory. It uses WMI to monitor the processes. I tried using Process class first and tried to access the TotalProcessorTime but it gave me "Access Denied" for processes like mysqld. For some processes, I did not get the WorkingSet and so on. Then I tried using PerformanceCounter to get the CPU and Memory usage of process. It was too expensive to query Performance Counter for each process. So, I had to rely on WMI to give me the information.

Pretty straight forward. The only cool thing to learn here is I declared the ManageObjectSearcher as a private variable, not a local variable to this function because it seems creating and disposing it every time the GetUsage function is called is very expensive. CPU was getting 20% for about 30 seconds on WMIpserv.exewhenever I tried to create and dispose the searcher.

Closing a process turned out to be a R&D challenge. You can kill a process by calling Process.Kill, but that terminates the process abnormally. If you are killing Outlook this way, it causes data corruption. So, you have to gracefully close the application. However, if some app is stuck and taking 100% CPU, trying to close it gracefully does not work. You have to take drastic measures. In that case, killing it is only the solution.

Here it calls the Process.CloseMainWindow function to send a shutdown message to the process. If the process has a visual window, it will receive the message and hopefully it will close itself soon. If there's no visual window, then it will not receive the message and it will not shutdown. So, we will have to kill it.

Even if some process receives the shutdown message, it may not terminate properly if it's stuck in some infinite loop. In that case, we need to check back after a while if it's still running and then kill it.

This function is fired from a timer. We wait for a while and then go for the kill. First check, if the process is still lying around. If it is, then kill it.

Another interesting topic is memory usage. As you know, Windows Forms apps when started, take up about 10 MB to 15 MB memory. It's too much for a utility which is running in the background and trying to save you some memory. It's because when .NET WinForms libraries load, they load a lot of stuff hoping you would need it and it would save additional load time. So, I had to force .NET to flush out any unused stuff. I have a MemoryHelper which does this:

First it forces a Garbage Collection, then it calls the EmptyWorkingSet function on psapi.dll to flush out the working set, which is the physical memory allocation. I don't know whether or not it works, but at least Taskbar shows that the app now takes only 5 MB memory. Super!

Conclusion

Hope CPUAlert will save you from slowing down your PC or burning out laptop batteries quickly. If you find it useful, please spread the love. Start by voting for this article.

This is a quick and dirty way i would get around MSs short sightedness it (probably needs a bit more work for general use, but gets the job done), using a proxy class that implements ICustomTypeDescriptor (if VB bothers you, you can convert it with http://www.developerfusion.com/tools/convert/vb-to-csharp/), a much easier way though more maintenance if you add properties regularly would probably be to just create a wrapper class and add new properties to it at the same time as adding new settings.

Its pretty self explanatory, but if you would like any clarification on any of it, just let me know.

You could even have it so you could prefix the property name with something like USRVIS_ to signify the user can see the setting, or set up advanced config options that are usually hidden from some users, and only add it to the proxy if that existed (and strip it from the display name), or filter the properties based on the existence of the System.Configuration.ApplicationScopedSettingAttribute or System.Configuration.UserScopedSettingAttribute to show user/app wide config settings separately (or place them in difference categories).

Is it overkill just to replace some _ with a space, maybe, but then i have been known to be fussy about some things. Anyway, hope it helps someone.