Managed heap OutOfMemory - c#

EDIT: I reformulated it to be a question and moved the answer to the answers part...
In a relatively complex multithreaded .NET application I experienced OutOfMemoryException even in the cases I could think there is no reason for it.
The situation:
The application is 32bit.
The application creates lot of (thousands) short lived objects that are considered small (less than approx. 85kB).
Additionaly it creates some (hundreds) short lived objects that are considered large (greater than approx. 85kb). This implies these objects are allocated at LOH (large object heap).
Both classes for these objects define finalizer (~MyFinalizer(){...}).
The symptoms:
OutOfMemoryException
Looking at the app via memory profiler, there are thousands of the small objects eligible for collection, but not collected and thus block large amount of memory.
The questions:
Why the app exhausts entire heap?
Why there is lot of "dead" objects still present in the memory?

After some deep investigation I have found the reason. As it took some time, I would like to make it easy for others suffering the same problem.
The reasons:
App has only approx 2GB of virtual address space.
The LOH is by design not compacted and thus might get fragmented very quickly, but for the mentioned count of large objects it should not be any problem.
Due to the design of the Garbage Collector, if there is an object defining the finalizer (even just empty), it is considered as Gen2 object and is placed into GC's finalization queue. This implies, until it is finalized (the MyFinalizer called) it just blocks the memory. In the case of mentioned app the GC thread running the finalizers didn't get the chance to do its work as quickly as needed and thus the heap was exhausted.
The Solution:
Do not use the finalizer for such "dynamic" objects (high volume, short life), workaround the finalization code in other way...
Very useful sources:
The Dangers of the Large Object Heap
Garbage Collection
Will the Garbage Collector call Dispose for me?

Try using a profiler, such as:
ANTS Memory Profiler
ANTS Performance Profiler
Jetbrains Performance Profiler
For LOH force a GC with:
GC.Collect();
GC.WaitForPendingFinalizers();

Related

Does Server Collection Create A Seperate LOH Heap For Each Core? C#

From the research On Garbage Collection, Server Collection Allows for the creation of a separate thread for each CPU core that you have that runs a separate GC and Generational Heap. But I Wasn't Able to find anything On whether each thread gets its own LOH Heap Or There Is Just One LOH Heap Per App
Interesting question. It seems it does maintain a heap (small and large) per logical CPU, though not per thread. Which makes a lot of sense :)
Workstation and server garbage collection
Server GC
The following are threading and performance considerations for server garbage collection:
...
A heap and a dedicated thread to perform garbage collection are provided for each logical CPU, and the heaps are collected at the same time. Each heap contains a small object heap and a large object heap, and all heaps can be accessed by user code. Objects on different heaps can refer to each other.

Defragmentation of heap in c#?

I want to understand full complete working with heap in C#. I understand how the stack and heap work, but I didn't find any explanation (if it is possible) of heap defragmentation.
I read a lot about a problem with fragmentation when GC is allocating and deallocating memory blocks on heap.
So if someone can explain to me or give some good article about this concern and heap (memory) defragmentation.
If you know about how the heap works, I assume you know that there are several different kinds of heaps. See my answer here - Stack vs. Heap in .NET
So the 2 you are speaking of out of those I mention in that answer are the Large Object Heap (LOH) and the GC Heap (also called Ephemeral Heap).
Generally don't need to worry about heap fragmentation for .NET. GC for .NET works in 3 steps: mark, sweep, compact. Mark - scans for all rooted references and makes a list of those that are rooted - these are not eligible for garbage collection and will not be touched. Sweep - clears the memory for those items not on the list and clears the "marked bit" for items that were marked. Compact - moves the memory for the remaining rooted objects so it is in a contiguous block. One caveat to the Compact phase is that the LOH is NOT compacted at least as of the latest version of .NET 4.6.2. This was a design decision the CLR GC team made because of performance reasons and time it would take to move all of the memory to a contiguous block. There have been many, many performance improvements since .NET 1.0 so GC isn't the beast it used to be. In any case, the Heap for Gen 0, 1, and 2 are compacted. Thus, no need for worry about fragmentation there. For the most part, the LOH survives without fragmentation problems with the algorithm it implements. There are cases where you can get fragmentation on the LOH. This can be caused by several things - some of which are bad allocation patterns, frequent Full GC collections, etc. This can be combated by improving allocation patterns, allocating large chunks of memory as close together (programmatically) as possible, and object pooling.
As of .NET 4.5.1, there is a way to compact the LOH manually though I would strongly recommend against it for the reason that it is a huge performance hit for your app for 2 reasons:
it is time consuming
it clears any of the allocation pattern algorithm that the GC has collected over the lifetime of your app. While your app is running, the GC actually tunes itself by learning how your app allocates memory. As such, it becomes more efficient (to a certain point) the longer your app runs. When you execute GC.Collect() (or any overload of it), it clears all of the data the GC has learned - so it must start over. You can read more about how to manually compact the LOH here: https://blogs.msdn.microsoft.com/mariohewardt/2013/06/26/no-more-memory-fragmentation-on-the-net-large-object-heap/ (again, I recommend against it)
Info about GC mark, sweep, compact - https://blogs.msdn.microsoft.com/abhinaba/2009/01/30/back-to-basics-mark-and-sweep-garbage-collection/
Info about LOH allocation algorithm:
https://www.red-gate.com/simple-talk/dotnet/net-framework/the-dangers-of-the-large-object-heap/

Does CLR reuse object in LOH by default?

I read some posts and books about .Net/C#/CLR and so on, and found following slide in Microsoft's presentation of 2005 year:
GC takes time – “% time in GC” counter
If objects die in gen0 (survival rate is 0) it’s the ideal situation
The longer the object lives before being dead, the worse (with exceptions)
Gen0 and gen1 GCs should both be relatively cheap; gen2 GCs could cost a lot
LOH – different cost model
Temporary large objects could be bad
Should reuse if possible
My question is what does it mean Should reuse if possible ? Is it that CLR reuse allocated memory for new object in LOH or that user (developer in our case) should do it ?
I think that is a note to us, as implementers, not a note on how Microsoft works (so no, it does not automatically reuse objects). If you have a object on the LOH, and you immediate dispose it, the LOH can get fragmented very soon. That is why it says "Temporary large objects could be bad".
The other thing is in the same line: if you have a large object and you can reuse it, you prevent recreating that object and thus improve performance. This is true because you prevent the LOH to get fragmented faster and you lower the memory pressure. One specific thing that comes in mind here are large string objects. Those are ideal to reuse. The string intern pool is located on the LOH, so if you intern frequently used large strings, you do what it asks.
I agreed with Patrick's statement; CLR doesn't reuses object in LOH. These guidelines are for our implementation purposes.
Gen2 garbage collection process is very costly, so we need to avoid this. So we can do this by reusing the objects, because fragmentation process also performed and it will take more time in case of LOH. We can reuse these objects by using object pool.

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

Question about the garbage collector in .NET (memory leak)

I guess this is very basic but since I'm learning .NET by myself, I have to ask this question.
I'm used to coding in C, where you have to free() everything. In C++/.NET, I have read about the garbage collector. From what I understand, when an instance is no longer used (in the scope of the object), it is freed by the garbage collector.
So, having that in mind, I built a little testing application. But, it seems I didn't get something because when doing the same things a few times (like, opening a form, closing it, reopening it, etc), memory leaks. And big time.
I tried to look this up on Google but I didn't find anything good for a beginner.
Is the garbage collector really freeing every objects when no longer used or there are exceptions that I have to handle? What am I missing?
Are there free tools to look up for memory leaks?
Yeah, the garbage collector is freeing your objects when they're not used anymore.
What we usually call a memory leak in .NET is more like:
You're using external resources (that are not garbage collected) and forgetting to free them. This is solved usually by implementing the IDisposable interface.
You think there aren't references to a given object but indeed there are, somewhere and you're not using them any more but the garbage collector does not know about them.
In addition, memory is only reclaimed when needed, meaning the garbage collector activates at given times and performs a collection determining them what memory can be freed and freeing it. Until it does, the memory isn't claimed so it might look like memory is being lost.
Here, I think I'll provide a more complex answer just to clarify.
First, the garbage collector runs in its own thread. You have to understand that, in order do reclaim memory the garbage collector needs to stop all other threads so that he can follow up the reference chain an determine what depends on what. That's the reason memory isn't freed right away, a garbage collector imply certain costs in performance.
Internally the garbage collector manage memory in generations. In a very simplified way there are several generations for long lived, short lived and big size objects. The garbage collector moves the object from one generation to another each time its performs a collection which happens more often for short lived generation that for long lived one. It also reallocates objects to get you the most possible contiguous space so again, performing a collection is a costly process.
If you really want to see the effects of you freeing the form (when getting out of scope and having no more reference to it) you can call GC.Collect(). Do that just for testing, it's highly unwise to call Collect except for a very few cases where you know exactly what you're doing and the implications it will have.
A little more explaining about the Dispose method of the IDispose interface.
Dispose isn't a destructor in the usual C++ way, it isn't a destructor at all. Dispose is a way to deterministically get rid of unmanaged objects. An example: Suppose you call an external COM library that happens to allocate 1GB of memory due to what it is doing. If you have no Dispose that memory will sit there, wasting space until the GC inits a collection and reclaims the unmanaged memory by calling the actual object destructor. So if you want to free the memory right away you have to call the Dispose method but you're not "forced" to do so.
If you don't use IDisposable interface then you have to free you're unmanaged resources in the Finalize method. Finalize is automatically called from the object destructor when the GC attempts to reclaim the object. So if you have a proper finalize method the unmanaged memory will get freed either way. Calling Dispose will only make it deterministic.
What leads you to conclude that there are memory leaks? Under garbage collection, there is no guarantee that memory is freed immediately, and in general the GC doesn't kick in until your process memory reaches some threshold, or the available heap has been exhausted. (The exact heuristic is complicated and not important.) So the fact that your process's memory goes up and doesn't go down doesn't necessarily mean that there's a bug. It might just be that the GC didn't get around to cleaning up your process yet.
Additionally, are you sure that there are no references to your objects? It's possible that you have references that you aren't aware of. Most memory leaks in .NET applications are because people don't realize that their memory is still being referenced somewhere.
Task Manager is a terrible way to examine your memory usage. If you want to study how the garbage collector works, install the CLR Profiler and use it to analyze your application. It will tell you exactly what the garbage collector is doing.
See How To: Use CLR Profiler.
I'm adding this as an answer rather than a comment on the question, but this follows-up a question asked by the OP in a comment:
using statement on MSDN.
IDisposable interface on MSDN.
Here is the crux of the issue: what you're used to as far as object destructors is gone. Everything you've been told about how to code correctly is screaming up from your subconscious, saying this can't be true, and if it is true, it's wrong and terrible. It's very different; it's hard to remember how much I really despised it at first (I was a proud C++ developer).
I personally promise you: it's going to be OK!
Here's another good thing to read:
Destructors and Finalizers in Visual C++.
The GC will not necessarily actually free things at the moment the object is no longer referenced. The GC will collect it at some time in the future - you don't know exactly when, but if memory is needed, the GC will perform a collection if necessary.
If you just want to figure out if you have a memory leak or not, have a look at perfmon which ships with your copy of windows:
In particular the .NET CLR Memory counter bytes in all heaps, if this number is steadily growing you have a leak.
You can even dig deeper by comparing the Gen 2 heap size to the Large Object Heap Size. If the former is growing steadily you have a large blobs of data leaking.
Once you confirm there is a leak, you can attach with windbg and use the sos extensions to determine what is leaking.
If you can afford to spend a few bucks have a look at the .NET Memory Profiler.
There are free tools available to look at the managed heap in .Net, using the SOSEX extensions to WinDBG and SOS, it is possible to run a program, pause it, then look at which objects exist on the stack and (more importantly) which other objects are holding references to them (roots) which will be preventing the the GC from collecting them.

Categories