views:

168

answers:

3

I have an application that periodically needs to process large blocks of data with a computationally trivial algorithm. It turns out I can also prevent slowing down the system from hard drive accesses by keeping the blocks of data in a memory cache. The application is a low-priority application so I'm working to minimize its impact on the system across the board, which means using extra memory (when available) to reduce the load on the CPU and hard drives. The cached data is just 64MB blocks of bytes, and the more of them I have in memory the less overhead the program will have on the drives.

What I need to do is dump the in-memory cache whenever any other application on the system needs more physical memory than is available, and do so fast enough that the user never feels the system slowing down due to high memory demands.

I'm particularly interested in how this would be accomplished in a .NET application.

+1  A: 

You could P/Invoke down to Win32 CreateMemoryResourceNotification API with the LowMemoryResourceNotification option. This returns a notification object that you can either poll (using QueryMemoryResourceNotification) or wait on (in a background thread; you'd need to use one of the Win32 wait methods rather than a .NET wait method, or possibly derive a custom class from WaitHandle to encapsulate the Win32 object). You would respond by dropping the blocks from your cache and forcing a garbage collection; you'd have to test whether this is "fast enough that the user never feels the system slowing down."

Also, looking at the docs, the threshold for raising a low-memory notification is really low memory (32 MB on a 4 GB system!). I suspect by that time the user might already be feeling the slowdown, and paging your app into memory to dump its blocks might cause perceptible disk access. Again, you could evaluate this with testing.

itowlson
That's an interesting idea, but as you mentioned it looks like I'll need more notification than that provides. You get a +1 for mentioning a new type derived from `SafeWaitHandle` that handles the memory blocks.
280Z28
+2  A: 

One option would be to use the ASP.NET Cache, which scavenges items in response to low memory. While Microsoft attaches a big warning that it is only tested within an ASP.NET application, there's nothing to stop you accessing HttpRuntime.Cache in any application, and in practice it has worked when I've done so.

If that feels dirty and wrong (or just doesn't do quite what you need), we can at least draw inspiration from how ASP.NET knows to scavenge the cache. It periodically calls the kernel's GlobalMemoryStatusEx to find out the memory available. Specifically, the dwMemoryLoad property of the returned structure is the percentage of total memory in use. By default, ASP.NET considers memory to be running out when this reaches 90%.

There's some example code to call this yourself here.

stevemegson
It only feels "dirty and wrong" because I'm minimizing the number of assemblies referenced by the application. I'll check out the API you mentioned - I think a periodic poll on a low priority thread could give me what I need, especially if I predict the need for memory by the current value and its derivative, and the current CPU usage.
280Z28
A: 

You can use the WeakReference class to have weak references to the memory blocks. This allows for the garbage collector to remove the objects if neccessary.

Yor objects would be in the large objects heap, as they are larger than 85 kb. The most common garbage collection only looks at the first generation heap, so it would not collect your objects. If the system notifies the .NET system that it's running out of memory, the garbage collector will run a more thorough collection, removing your objects in the large objects heap.

Guffa
Why the downvote? If you don't comment on what it is that you don't like, it's rather pointless.
Guffa
This doesn't address memory demands from other applications, and it relies too much on exactly when/where I have a normal reference or just a weak reference to the cache items. I need to handle the memory problems even if I'm actively processing one of the blocks.
280Z28
280Z28
@280Z28: Why do you think that it doesn't address memory demands from other applications? If the system doesn't know those demands, how could you possibly find them out otherwise? And I don't understand what you mean about handling memory probmes while processing a block... Do you want to abort the current processing?
Guffa
Yes, it would stop the processing and some minutes later would check the available memory to see if it should try again.
280Z28