Does CLR reuse object in LOH by default? - c#

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.

Related

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/

Managed heap OutOfMemory

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();

Large Object Heap Compaction, when is it good?

First off, how big is considered large? Is there anyway to determine how large an object is in heap?
.Net 4.5.1 comes with this LargeObjectHeapCompactionMode:
After the LargeObjectHeapCompactionMode property is set to
GCLargeObjectHeapCompactionMode.CompactOnce, the next full blocking
garbage collection (and compaction of the LOH) occurs at an
indeterminate future time. You can compact the LOH immediately by
using code like the following:
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
From what I've heard, it's a bad thing to compact LOH! So, which one is worst? Compact LOH or having LOH fragmentation?
Allocations >= 85 KB go onto the LOH. Compacting the LOH is not bad -- it's just that LOH fragmentation isn't something the great majority of apps need to worry about, so for them it's not worth the expense of compacting.
Fragmentation occurs when you allocate several large objects and they all get taken from the same page of address space, then let some of those objects get collected. The remaining free space in that page might be unusable because it is too small, or even simply "forgotten" in the sense that the allocator won't ever reconsider using it again.
Eventually there are fewer and fewer clean pages to use, so the allocator will start to slow down as it forcibly moves objects or even start throwing OutOfMemory exceptions. Compaction moves those objects to new pages, reclaiming that free space.
Does your app have this object usage pattern? Most don't. And on 64-bit platforms, you might not even notice it as there's quite a bit more address space to fragment before it becomes a huge issue.

C# and .Net Garbage collector performance

I am trying to make a game in C# and .NET, and I was planning to implement messages that update the game objects in the game world. These messages would be C# reference objects.
I want this approach because doing it this way would be easier to send them over a network if I want the game to be multiplayer.
But if I have a lot of messages, won't it be quite stressful for the garbage collector? And won't that affect gameplay? The message classes themselves are quite small with 4 or 5 members at most.
These messages will be generated a couple of times per second for each object in the game world.
In .NET the garbage collector has 3 generations, generation 0, generation 1 and generation 2. Every Time the GC fails to collect an object in a generation, that object will be promoted to the next generation.
You could potentially run into issues if your objects are larger than 85kb. These objects will be automatically stored in the large object heap. The large object heap will be automatically collected in the following situations:
Allocations exceed the large object heaps threshold.
System is in a low memory situation.
System.GC.Collect is called on generation 2.
The problem is that when the large object heap is collected, the memory for the objects is deallocated but the LOH is not compacted. Because the LOH is fragmented, you could potentially get SystemOutOfMemory exceptions thrown if there isn't a space big enough for your object on the LOH.
Techniques such as object pooling are commonly used to improve performance of the LOH.
http://en.wikipedia.org/wiki/Object_pool_pattern
Source: http://msdn.microsoft.com/en-us/magazine/cc534993.aspx
UPDATE: .Net 4.5.1 will allow you to do on-demand compaction of the LOH within your application using the GC.Collect API.
The GC in later versions, but more precisely 4.5, runs asynchronously for generations level 0 and 1. This has highly reduced the impact of GC.
If your objects are short-lived they should not pass from generation level 0 most of the time. Level 0 is the fastest generation to clean up by the GC.
Bottom line, I would not consider prematurely optimizing my code for fear of GC performance.
Premature optimization is the root of all evil by
DonaldKnuth
Personally, i'd recommend this article for a deeper understanding

Understanding Memory Performance Counters

[Update - Sep 30, 2010]
Since I studied a lot on this & related topics, I'll write whatever tips I gathered out of my experiences and suggestions provided in answers over here-
1) Use memory profiler (try CLR Profiler, to start with) and find the routines which consume max mem and fine tune them, like reuse big arrays, try to keep references to objects to minimal.
2) If possible, allocate small objects (less than 85k for .NET 2.0) and use memory pools if you can to avoid high CPU usage by garbage collector.
3) If you increase references to objects, you're responsible to de-reference them the same number of times. You'll have peace of mind and code probably will work better.
4) If nothing works and you are still clueless, use elimination method (comment/skip code) to find out what is consuming most memory.
Using memory performance counters inside your code might also help you.
Hope these help!
[Original question]
Hi!
I'm working in C#, and my issue is out of memory exception.
I read an excellent article on LOH here ->
http://www.simple-talk.com/dotnet/.net-framework/the-dangers-of-the-large-object-heap/
Awesome read!
And,
http://dotnetdebug.net/2005/06/30/perfmon-your-debugging-buddy/
My issue:
I am facing out of memory issue in an enterprise level desktop application. I tried to read and understand stuff about memory profiling and performance counter (tried WinDBG also! - little bit) but am still clueless about basic stuff.
I tried CLR profiler to analyze the memory usage. It was helpful in:
Showing me who allocated huge chunks of memory
What data type used maximum memory
But, both, CLR Profiler and Performance Counters (since they share same data), failed to explain:
The numbers that is collected after each run of the app - how to understand if there is any improvement?!?!
How do I compare the performance data after each run - is lower/higher number of a particular counter good or bad?
What I need:
I am looking for the tips on:
How to free (yes, right) managed data type objects (like arrays, big strings) - but not by making GC.Collect calls, if possible. I have to handle arrays of bytes of length like 500KB (unavoidable size :-( ) every now and then.
If fragmentation occurs, how to compact memory - as it seems that .NET GC is not really effectively doing that and causing OOM.
Also, what exactly is 85KB limit for LOH? Is this the size of the object of the overall size of the array? This is not very clear to me.
What memory counters can tell if code changes are actually reducing the chances of OOM?
Tips I already know
Set managed objects to null - mark them garbage - so that garbage collector can collect them. This is strange - after setting a string[] object to null, the # bytes in all Heaps shot up!
Avoid creating objects/arrays > 85KB - this is not in my control. So, there could be lots of LOH.
3.
Memory Leaks Indicators:
# bytes in all Heaps increasing
Gen 2 Heap Size increasing
# GC handles increasing
# of Pinned Objects increasing
# total committed Bytes increasing
# total reserved Bytes increasing
Large Object Heap increasing
My situation:
I have got 4 GB, 32-bit machine with Wink 2K3 server SP2 on it.
I understand that an application can use <= 2 GB of physical RAM
Increasing the Virtual Memory (pagefile) size has no effect in this scenario.
As its OOM issue, I am only focusing on memory related counters only.
Please advice! I really need some help as I'm stuck because of lack of good documentation!
Nayan, here are the answers to your questions, and a couple of additional advices.
You cannot free them, you can only make them easier to be collected by GC. Seems you already know the way:the key is reducing the number of references to the object.
Fragmentation is one more thing which you cannot control. But there are several factors which can influence this:
LOH external fragmentation is less dangerous than Gen2 external fragmentation, 'cause LOH is not compacted. The free slots of LOH can be reused instead.
If the 500Kb byte arrays are referring to are used as some IO buffers (e.g. passed to some socket-based API or unmanaged code), there are high chances that they will get pinned. A pinned object cannot be compacted by GC, and they are one of the most frequent reasons of heap fragmentation.
85K is a limit for an object size. But remember, System.Array instance is an object too, so all your 500K byte[] are in LOH.
All counters that are in your post can give a hint about changes in memory consumption, but in your case I would select BIAH (Bytes in all heaps) and LOH size as primary indicators. BIAH show the total size of all managed heaps (Gen1 + Gen2 + LOH, to be precise, no Gen0 - but who cares about Gen0, right? :) ), and LOH is the heap where all large byte[] are placed.
Advices:
Something that already has been proposed: pre-allocate and pool your buffers.
A different approach which can be effective if you can use any collection instead of contigous array of bytes (this is not the case if the buffers are used in IO): implement a custom collection which internally will be composed of many smaller-sized arrays. This is something similar to std::deque from C++ STL library. Since each individual array will be smaller than 85K, the whole collection won't get in LOH. The advantage you can get with this approach is the following: LOH is only collected when a full GC happens. If the byte[] in your application are not long-lived, and (if they were smaller in size) would get in Gen0 or Gen1 before being collected, this would make memory management for GC much easier, since Gen2 collection is much more heavyweight.
An advice on the testing & monitoring approach: in my experience, the GC behavior, memory footprint and other memory-related stuff need to be monitored for quite a long time to get some valid and stable data. So each time you change something in the code, have a long enough test with monitoring the memory performance counters to see the impact of the change.
I would also recommend to take a look at % Time in GC counter, as it can be a good indicator of the effectiveness of memory management. The larger this value is, the more time your application spends on GC routines instead of processing the requests from users or doing other 'useful' operations. I cannot give advices for what absolute values of this counter indicate an issue, but I can share my experience for your reference: for the application I am working on, we usually treat % Time in GC higher than 20% as an issue.
Also, it would be useful if you shared some values of memory-related perf counters of your application: Private bytes and Working set of the process, BIAH, Total committed bytes, LOH size, Gen0, Gen1, Gen2 size, # of Gen0, Gen1, Gen2 collections, % Time in GC. This would help better understand your issue.
You could try pooling and managing the large objects yourself. For example, if you often need <500k arrays and the number of arrays alive at once is well understood, you could avoid deallocating them ever--that way if you only need, say, 10 of them at a time, you could suffer a fixed 5mb memory overhead instead of troublesome long-term fragmentation.
As for your three questions:
Is just not possible. Only the garbage collector decides when to finalize managed objects and release their memory. That's part of what makes them managed objects.
This is possible if you manage your own heap in unsafe code and bypass the large object heap entirely. You will end up doing a lot of work and suffering a lot of inconvenience if you go down this road. I doubt that it's worth it for you.
It's the size of the object, not the number of elements in the array.
Remember, fragmentation only happens when objects are freed, not when they're allocated. If fragmentation is indeed your problem, reusing the large objects will help. Focus on creating less garbage (especially large garbage) over the lifetime of the app instead of trying to deal with the nuts and bolts of the gc implementation directly.
Another indicator is watching Private Bytes vs. Bytes in all Heaps. If Private Bytes increases faster than Bytes in all Heaps, you have an unmanaged memory leak. If 'Bytes in all Heaps` increases faster than 'Private Bytes' it is a managed leak.
To correct something that #Alexey Nedilko said:
"LOH external fragmentation is less dangerous than Gen2 external
fragmentation, 'cause LOH is not compacted. The free slots of LOH can
be reused instead."
is absolutely incorrect. Gen2 is compacted which means there is never free space after a collection. The LOH is NOT compacted (as he correctly mentions) and yes, free slots are reused. BUT if the free space is not contiguous to fit the requested allocation, then the segment size is increased - and can continue to grow and grow. So, you can end up with gaps in the LOH that are never filled. This is a common cause of OOMs and I've seen this in many memory dumps I've analyzed.
Though there are now methods in the GC API (as of .NET 4.51) that can be called to programatically compact the LOH, I strongly recommend to avoid this - if app performance is a concern. It is extremely expensive to perform this operation at runtime and and hurt your app performance significantly. The reason that the default implementation of the GC was to be performant which is why they omitted this step in the first place. IMO, if you find that you have to call this because of LOH fragmentation, you are doing something wrong in your app - and it can be improved with pooling techniques, splitting arrays, and other memory allocation tricks instead. If this app is an offline app or some batch process where performance isn't a big deal, maybe it's not so bad but I'd use it sparingly at best.
A good visual example of how this can happen is here - The Dangers of the Large Object Heap and here Large Object Heap Uncovered - by Maoni (GC Team Lead on the CLR)

Categories