views:

187

answers:

3

I know that memory usage is a very complex issue on Windows.

I am trying to write a UI control for a large application that shows a 'percentage of memory used' number, in order to give the user an indication that it may be time to clear up some memory, or more likely restart the application.

One implementation used ullAvailVirtual from MEMORYSTATUSEX as a base, then used HeapWalk() to walk the process heap looking for additional free memory. The HeapWalk() step was needed because we noticed that after a while of running the memory allocated and freed by the heap was never returned and reported by the ullAvailVirtual number. After hours of intensive working, the ullAvailVirtual number no longer would accurately report the amount of memory available.

However, this method proved not ideal, due to occasional odd errors that HeapWalk() would return, even when the process heap was not corrupted. Further, since this is a UI control, the heap walking code was executing every 5-10 seconds. I tried contacting Microsoft about why HeapWalk() was failing, escalated a case via MSDN, but never got an answer other than "you probably shouldn't do that".

So, as a second implementation, I used PagefileUsage from PROCESS_MEMORY_COUNTERS as a base. Then I used VirtualQueryEx to walk the virtual address space adding up all regions that weren't MEM_FREE and returned a value for GetMappedFileNameA(). My thinking was that the PageFileUsage was essentially 'private bytes' so if I added to that value the total size of the DLLs my process was using, it would be a good approximation of the amount of memory my process was using.

This second method seems to (sorta) work, at least it doesn't cause crashes like the heap walker method. However, when both methods are enabled, the values are not the same. So one of the methods is wrong.

So, StackOverflow world...how would you implement this?

  • which method is more promising, or do you have a third, better method?
  • should I go back to the original method, and further debug the odd errors?
  • should I stay away from walking the heap every 5-10 seconds?

Keep in mind the whole point is to indicate to the user that it is getting 'dangerous', and they should either free up memory or restart the application. Perhaps a 'percentage used' isn't the best solution to this problem? What is? Another idea I had was a color based system (red, yellow, green, which I could base on more factors than just a single number)

A: 

Hi,

Have a look at the following article .NET and running processes

It uses WMI to check for the memory usage of processes, specifically using the

System.Diagnostics.Process

and another link on how to use WMI in C#: WMI Made Easy for C#

Hope this helps.

Riaan
Clearly state win32 not C#.
pj4533
Hi,You can still use WMI in any WIN32 language, not just C#. This was just a baseline from my point of view.Sorry for the misunderstanding.
Riaan
A: 

The place to start is probably GetProcessMemoryInfo(). This fills in a structure for you that has, among other things, the current working set in bytes.

jeffamaphone
+1  A: 

Yes, the Windows memory manager was optimized to fulfill requests for memory as quickly and efficiently possible, it was not optimized to easily measure how much space is used. The first downfall is that heap blocks that are released are rarely unmapped. They are simply marked as "free", to be used by the next allocation. That's why VirtualQueryEx() cannot work.

The problem with HeapWalk is that you have to lock the heap (HeapLock) so that it can walk it without the heap allocation changing. That lock can have very detrimental side-effects. Quoting:

Walking a heap may degrade performance, especially on symmetric multiprocessing (SMP) computers. The side effects may last until the process ends.

Even then, the number you get back is pretty meaningless. A program never runs out of free space, it runs out of a large enough contiguous chunk of memory to fulfill the request. No happy answers I'm afraid. Except one: a 64-bit operating system cost less than two hundred bucks.

Hans Passant
Yeah... I hear that. I still figure there has to be a way to COMMUNICATE the situation to the user in a useful way. Even if it isn't in the form of a number. And yeah, our app is stuck in 32bit land for now, so the best we do is get heavy duty users on a 64bit OS so they can access all 4gb.
pj4533
Why don't you do it the other way around? Replace malloc/free or the new/delete operator with your own so you can track how much memory is allocated. The user will get a feel for the red zone.
Hans Passant
Yes, this is another method I had thought of implementing, but honestly I was a little hesitant simply because our application is so large I was afraid I wouldn't be able to catch all of our subsystems and components. But I suppose it is my best bet at this point, so I think I am going to give it a shot. Thanks.
pj4533
I did some research on globally replacing new/delete, and it looks like that is a whole other can of worms. After reading questions here and a few google searches it seems:1) a 'global' override is on a per module basis (DLLs, plugins and other modules won't know anything about my new/delete implementation)2) I can't overload both new and delete, I have to override them, which could lead to a less optimized implementation.
pj4533