Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Garbage Collection - What does it affect?

We have a situation where we are considering forcing a garbage collection on a server that is very low on RAM (3.6/4GB used on average). No, it's not really an option to upgrade this server unfortunately.

One of our service processes (written indirectly in C++ (don't ask...)) does work with the .NET components and then sleeps for 10 minutes. When that service is sleeping, it is often hanging on to 600MB of RAM that could be shared with other processes. Seems somehow related to WSE tracing being turned on for debugging. I can watch it wake up and GC on the next iteration on the first COM call to .NET - however then the process does some work and by the time it goes to sleep the RAM use is back up around 600MB... well, you can see where this goes...

The Question: I'm considering adding a garbage collection just before the process goes to sleep. There are other services on this box that are doing .NET related tasks. When I call a garbage collection in this service process, does that GC affect all other .NET related processes on the box or just the process that requests the collection? I'm a bit worried about creating some sort of performance problem for processes outside of the one I care about.

like image 397
TheToasterThatCould Avatar asked Jan 08 '10 15:01

TheToasterThatCould


2 Answers

It will only affect the process that is calling GC.

like image 159
jsight Avatar answered Sep 27 '22 18:09

jsight


It just affects the process it's called in (but will affect all Application Domains in the process). However, be warned that this will not release the memory to the OS. If you want to release the memory to the OS, a way to do it is:

private static void minimizeMemory()
{
    GC.Collect(GC.MaxGeneration);
    GC.WaitForPendingFinalizers();
    SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle,
        (UIntPtr) 0xFFFFFFFF, (UIntPtr) 0xFFFFFFFF);
}

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetProcessWorkingSetSize(IntPtr process,
    UIntPtr minimumWorkingSetSize, UIntPtr maximumWorkingSetSize);

The big caveat here is why. Unless you're noticing that memory is thrashing or swapping is a performance bottleneck (or you're writing an end-user app), there's no real reason to be concerned about memory usage. Forcing a GC can be slow. Reducing the heap will cause the heap to need to be re-allocated from VM. In addition, the .NET GC is reactive, using program behavior to increase its efficiency. By forcing a collection, you don't allow the GC to tune itself to your program's behavior, further reducing performance.

I know this from experience -- I asked this question a while back and even came up with a timer-based class to call the method above after leaving a high-memory operation (run every 5 minutes). Following this, the process working set would reduce itself a lot -- by swapping it to disk. Over the next couple seconds, it would read back the most frequently used parts, a couple minutes later (when the task was run again), it would again do a bunch of allocation. Timing (not even profiling) the process showed that with the collection, there was about a 0.2s (!) slowdown during the allocation of VM from the OS for the task.

like image 20
Robert Fraser Avatar answered Sep 27 '22 20:09

Robert Fraser