Garbage collection runs too late - causes OutOfMemory exceptions - c#

Was wondering if anyone could shed some light on this.
I have an application which has a large memory footprint (& memory churn). There aren't any memory leaks and GCs tend to do a good job of freeing up resources.
Occasionally, however, a GC does not happen 'on time', causing an out of memory exception. I was wondering if anyone could shed any light on this?
I've used the REDGate profiler, which is very good - the application has a typical 'sawtooth' pattern - the OOMs happen at the top of the sawtooth. Unfortunately the profiler can't be used (AFAIK) to identify sources of memory churn.
Is it possible to set a memory 'soft limit', at which a GC should be forced? At the moment, a GC is only performed when the memory is at its absolute limit, resulting in OOMs.

It shouldn't really be possible for a Garbage Collection to 'not to happen in time'. They happen when a new memory allocation would push Gen-0 past a certain limit. Thus they always happen before a memory allocation would push the memory past its limit. This happens so many times a day throughout the world I would be surprised if any bugs weren't well known about.
Have you considered that you might actually be allocating more memory than is available? The OS only lets you access 2GB on most 32-bit machines.
There are some other possibilities:
Is your application using un-managed memory?
Is your application Pinning any memory? If so that could cause a fragmentation issue especially if you aren't releasing pin.

If you use a lot of memory and you garbage collect a lot I guess you should consider the "Flyweight" design pattern.
As an example, if you garbage collect a lot of strings, see String.Intern(string s).
Msdn reference

You can use GC.collect() to force the garbage collector to do its work. But it is not preferable.
Use memory profiles like(memprofiler) to detect the leaks. Almost all your code performs leaks at some points.

Related

Weird out of memory exceptions [duplicate]

If you application is such that it has to do lot of allocation/de-allocation of large size objects (>85000 Bytes), its eventually will cause memory fragmentation and you application will throw an Out of memory exception.
Is there any solution to this problem or is it a limitation of CLR memory management?
Unfortunately, all the info I've ever seen only suggests managing risk factors yourself: reuse large objects, allocate them at the beginning, make sure they're of sizes that are multiples of each other, use alternative data structures (lists, trees) instead of arrays. That just gave me an another idea of creating a non-fragmenting List that instead of one large array, splits into smaller ones. Arrays / Lists seem to be the most frequent culprits IME.
Here's an MSDN magazine article about it:
http://msdn.microsoft.com/en-us/magazine/cc534993.aspx, but there isn't that much useful in it.
The thing about large objects in the CLR's Garbage Collector is that they are managed in a different heap.
The garbage collector uses a mechanism called "Compacting", which is basically fragmentation and re-linkage of objects in the regular heap.
The thing is, since "compacting" large objects (copying and re-linking them) is an expensive procedure, the GC provides a different heap for them, which is never being compacted.
Note also that memory allocation is contiguous. Meaning if you allocate Object #1 and then Object #2, Object #2 will always be placed after Object #1.
This is probably what's causing you to get OutOfMemoryExceptions.
I would suggest having a look at design patterns like Flyweight, Lazy Initialization and Object Pool.
You could also force GC collection, if you're suspecting that some of those large objects are already dead and have not been collected due to flaws in your flow of control, causing them to reach higher generations just before being ready for collection.
A program always bombs on OOM because it is asking for a chunk of memory that's too large, never because it completely exhausted all virtual memory address space. You could argue that's a problem with the LOH getting fragmented, it is just as easy to argue that the program is using too much virtual memory.
Once a program goes beyond allocating half the addressable virtual memory (a gigabyte), it is really time to either consider making its code smarter so it doesn't gobble so much memory. Or making a 64-bit operating system a prerequisite. The latter is always cheaper. It doesn't come out of your pocket either.
Is there any solution to this problem or is it a limitation of CLR memory management?
There is no solution besides reconsidering your design. And it is not a problem of the CLR. Note, the problem is the same for unmanaged applications. It is given by the fact, that too much memory is used by the application at the same time and in segments laying 'disadvantageous' out in memory. If some external culprit has to be pointed at nevertheless, I would rather point at the OS memory manager, which (of course) does not compact its vm address space.
The CLR manages free regions of the LOH in a free list. This in most cases is the best what can be done against fragmentation. But since for really large objects, the number of objects per LOH segment decreases - we eventually end up having only one object per segment. And where those objects are positioned in the vm space is completely up to the memory manager of the OS. This means, the fragmentation mostly happens on the OS level - not on the CLR. This is an often overseen aspect of heap fragmentation and it is not .NET to blame for it. (But it is also true, fragmentation can also occour on the managed side like nicely demonstrated in that article.)
Common solutions have been named already: reuse your large objects. I up to now was not confronted with any situation, where this could not be done by proper design. However, it can be tricky sometimes and therefore may be expensive though.
We were precessing images in multiple threads. With images being large enough, this also caused OutOfMemory exceptions due to memory fragmentation. We tried to solve the problem by using unsafe memory and pre-allocating heap for every thread. Unfortunately, this didn't help completely since we relied on several libraries: we were able to solve the problem in our code, but not 3rd party.
Eventually we replaced threads with processes and let operating system do the hard work. Operating systems have long ago built a solution for memory fragmentation, so it's unwise to ignore it.
I have seen in a different answer that the LOH can shrink in size:
Large Arrays, and LOH Fragmentation. What is the accepted convention?
"
...
Now, having said that, the LOH can shrink in size if the area at its end is completely free of live objects, so the only problem is if you leave objects in there for a long time (e.g. the duration of the application).
...
"
Other then that you can make your program run with extended memory up to 3GB on 32bit system and up to 4 GB on 64bit system.
Just add the flag /LARGEADDRESSAWARE in your linker or this post build event:
call "$(DevEnvDir)..\tools\vsvars32.bat"
editbin /LARGEADDRESSAWARE "$(TargetPath)"
In the end if you are planning to run the program for a long time with lots of large objects you will have to optimize the memory usage and you might even have to reuse allocated objects to avoid garbage collector which is similar in concept, to working with real time systems.

How can I tell if the .Net 3.5 garbage collector has run?

I have an application that creates trees of nodes, then tosses them and makes new trees.
The application allocates about 20 MB upon startup. But I tried loading a large file of nodes many times, and the allocated memory went above 700 MB. I thought I would see memory being freed by the garbage collector on occasion.
The machine I'm on has 12 GB of RAM, so maybe it's just that such a "small" amount of memory being allocated doesn't matter to the GC.
I've found a lot of good info on how the GC works, and that it's best not to tell it what to do. But I wanted to verify that it's actually doing anything, and that I'm not somehow doing something wrong in the code that prevents my objects from being cleaned up.
The GC generally runs when either of the scenarios below occur:
You call GC.Collect (which you shouldn't)
Gen0's budget is exhausted
There are some other scenarios as well, but I'll skip those for now.
You didn't tell us how you measured the memory usage, but if you're looking at the memory usage of process itself (e.g. through task manager), then you may not see the numbers you expect. Remember that the .NET runtime essentially has its own memory manager that handles memory usage on behalf of you managed application. The runtime tries to be smart about it so it doesn't allocate and free memory to the OS all the time (those are expensive operations). This question may be relevant as well.
If you're concerned about memory leaks have a look at some of the answers here.
When does the .Net 3.5 garbage collector run?
I thought I would see memory being freed by the garbage collector on occasion.
Since the GC is non-deterministic, you won't be able to necessarily determine when it is going to issue a collection. Short answer: It will run when needed. Trying to analyze your code and predict or assume it should be running at a certain time usually ends up down a rabbit hole.
Answer to: do I leak objects or GC have not need to run yet?
Use memory profiler to see what objects are allocated. As basic step - force garbage collection (GC.Collect) and check out if allocated memory (GC.GetTotalMemory) seems to be reasonable.
If you want to make sure that you're not leaving any unwanted object behind you can use dotTrace memory profiler. It allows you to take two snapshots of objects in memory (taken some time apart) and compare them. You will can clearly see if any old nodes are still hanging around and what is keeping a reference to them and stops them from being collected.
You may have the managed equivalent of a memory leak. Are you maintaining stale references to these objects (i.e., do you have a List<T> or some other object which tracks these nodes)?
Are the subscribing to an event of an object that is not going out of scope? A reference to the subscribee of an event is maintained, so if you don't detach it will keep your objects alive.
You may also be forgetting to Dispose of objects that implement IDisposable. Can't say without seeing your code.
The exact behavior of the GC is implementation defined. You should design your application such that it does not matter. If you need deterministic memory management then you are using the wrong language. Use a tool (RedGate's ANTS profiler will do) to see if you are leaking references somewhere.
This comic is the best way to explain this topic :)
You can monitor the garbage collector activity in .NET 4.0 and beyond with GC.RegisterForFullGCNotification as described in this link: http://www.abhisheksur.com/2010/08/garbage-collection-notifications-in-net.html

Long running windows service with a memory leak? Or just looks like one?

This sounds a little odd, but I'm not sure if my process has a memory leak or not, and I was hoping to get some information.
I was recently assigned an investigation into why a windows service in production was consuming roughly a gig of ram (the server it is running on has 8 gigs). This is outside of my experience as a developer, but it's been a very good chance for me to read up on how garbage collection is working on msdn and other sources. But at this point I'm very confused about /when/ collection actually runs, on this point, ever article I read is vague.
1) I have found a specific operation that increases memory by ~30kb each time it is executed.
2) I have very carefully gone over the code and believe that I am properly closing everything, and removing references
3) I have used several memory profilers, all of them seem to indicate that my old objects are linked to the gc.
4) If I leave the process absolutely idle for a few days, the memory usage suddenly plummets down to ~8 megs
So based on this, I'm not even sure I have a memory leak. Given that GC is an expensive process, is it possible that I grew to 1 gig in production just because there was still free ram to be had, and acquiring it was "cheaper" than running GC? Especially given that this service is run ~6 times a second? If this is the case, what options do I have? I am of the understanding that I cannot forceably trigger GC, do I have any resort?
Thank you for any input you might have, I realize memory leaks and gc in csharp is a deep topic and if there's a particularly helpful read on the subject, I'd be happy to be pointed that way as well.
You certainly CAN force a garbage collection - just call GC.Collect. It's not that you can't but that the garbage collector usually does a better job of figuring out when it should run than you do. But here, you can call it explicitly - as a debugging tool - to see whether or not the allocated memory is eligible for collection.
Memory leak usually implies that memory is never deallocated and process eventually crashes with OutOfMemoryException. You are saying that it does get deallocated after a while
4) If I leave the process absolutely idle for a few days, the memory usage suddenly plummets down to ~8 megs
You certainly can force garbage collection using GC.Collect. But as others have said it is not a good long term solution. I highly recommend you to read about garbage collection in this book. If you still convinced that you have memory leak you can create a dump of the process in production environment using Process Explorer. And analyze it later using WinDbg. Unless you can use dotTrace or ANTS on production which would be a lot easier.

C# - Method of programmatically attempting to check for memory leak in block of code

I'm trying to see how feasible it is to attempt to accurately determine that there is a potential memory leak in a block of managed .NET code programmatically. The reason to do this would be to isolate some block of code that appears to be leaking memory, and to then use a standard profiler to further determine the actual cause of the leak. In my particular business case, I would be loading a 3rd party class that extends one of mine to check it for leaks.
The approach that first comes to mind is something like this:
Wait for GC to run.
Get the current allocated memory from the GC.
[Run block of managed code.]
Wait for GC to run.
Get the current allocated memory from the GC and subtract from the allocated memory recorded before running the block of code. Is it correct that the difference should theoretically be (near) 0 if all objects allocated in the block of code that was run were dereferenced appropriately and collected?
Certainly the immediate issue with this is that there will likely be waiting...and waiting...and waiting for the non-deterministic GC to run. If we skip that aspect, the calculation for determining if the block of code leaked any memory however can vary wildly, and would not necessarily be accurate, as some items may not have been collected at the time.
Does the above seem like my best option of attempting to determine somewhat accurately if a block of code is leaking memory? Or are there other working methods that are used in real-life? Thanks.
Personally, I would never dare to do memory profiling on my own. I'll fear that I either do not have the full knowledge and that it would take endless time to do so.
Instead I used successfully memory profilers like Red Gate's ANTS Memory Profiler.
While using ANTS Profiler is awesome it doesn't help if your problem is only seen in production.
Tess Ferrandez has a series of Labs that demonstrate how to debug production problems, including memory leaks. They focus on ASP.NET but it can be use for other types of applications as well.
You really need a Memory Profiler like this one: With that, you can:
start your application, take a memory snapshot (manually or from your code)
[Run block of managed code]
take another memory snapshot
compare the two snapshots and see which new objects are now on the managed heap
I believe it does exactly what you want to do, only far less painful. It also has some helpful filters like "show objects that are kept alive by delegates". It can also analyze memory dumps from a production system.

What causes memory fragmentation in .NET

I am using Red Gates ANTS memory profiler to debug a memory leak. It keeps warning me that:
Memory Fragmentation may be causing
.NET to reserver too much free memory.
or
Memory Fragmentation is affecting the size of the largest object that can be allocated
Because I have OCD, this problem must be resolved.
What are some standard coding practices that help avoid memory fragmentation.
Can you defragment it through some .NET methods? Would it even help?
You know, I somewhat doubt the memory profiler here. The memory management system in .NET actually tries to defragment the heap for you by moving around memory (that's why you need to pin memory for it to be shared with an external DLL).
Large memory allocations taken over longer periods of time is prone to more fragmentation. While small ephemeral (short) memory requests are unlikely to cause fragmentation in .NET.
Here's also something worth thinking about. With the current GC of .NET, memory allocated close in time, is typically spaced close together in space. Which is the opposite of fragmentation. i.e. You should allocate memory the way you intend to access it.
Is it a managed code only or does it contains stuff like P/Invoke, unmanaged memory (Marshal.AllocHGlobal) or stuff like GCHandle.Alloc(obj, GCHandleType.Pinned)?
The GC heap treats large object allocations differently. It doesn't compact them, but instead just combines adjacent free blocks (like a traditional unmanaged memory store).
More info here: http://msdn.microsoft.com/en-us/magazine/cc534993.aspx
So the best strategy with very large objects is to allocate them once and then hold on to them and reuse them.
The .NET Framework 4.5.1, has the ability to explicitly compact the large object heap (LOH) during garbage collection.
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
See more info in GCSettings.LargeObjectHeapCompactionMode

Categories