Memory Management
Tags: dotnet, programming, csharp
Published: 2023-04-02 00:15:30

When dealing with memory management on .NET garbage collection comes to mind as something that you have to constantly monitor. Understanding how your program interacts with the garbage collector makes a difference.

## Memory Allocation
How windows manages the heap and new allocations maintaining lists of free slots to reduce fragmentation, with native code applications you always have the option to maintain memory allocations as linear as possible with or without a custom allocation scheme. In .NET memory segments are controlled so objects are allocated near each other.

So when allocating an object the value to allocate it is set to the buffer information which will look for the next available byte and compare it against the end of the allocation buffer looking for a space where the object would fit, then is always better to work with multiple objects at a time rather than treating objects like they work in solitary.

When garbage collection occurs objects may be moved to different locations to free space on the segments which is expensive now that all references have to the objects have to point to a different -new- location.

## What can you do to help the GC?
First thing would be to reduce the memory allocated in the first place by for example:

- Removing unused fields.
- Keeping the size of primitives as small as possible
- Allocating memory upfront
- Initializing objects when and if needed

The general rule of thumb is that objects should have limited lifetime span so the garbage collector wouldn't have to considered them at all. On the other hand objects that you will use over a larger span have to be referenced once and should be kept and maintained to be reusable.

Small objects should be allocated right before using them and large objects must be allocated before hand so the cost of allocating them comes at an earlier point and not in the middle of processing your program.

Temporary objects must be set to null when no longer needed and the same applies for members from a static class when its values are no longer needed. Having nested object references become a problem as well because the objects lifetimes are hard to predict.

## Disposable Objects
Destructors are triggered by the garbage collector one after the other after a collection, as long as Dispose is called before a recollection the object will be eliminated without needing to call the destructor. So the Dispose pattern should be used instead of having a destructor with all the clean up logic in the Dispose method, this code should be as simple as it gets only touching memory that belongs to the object without any guarantee that it may be still valid.

## Marshalling
The problem with copying buffers is that data gets moved, for example when using LINQ to modify a list from an array of elements this data is copied to .NET memory space and then returned to your program memory space which has a huge cost.

Generally objects should be created and destroyed quickly other wise if you need them during the timespan of your program their reference should be kept forever. With static references objects live through the lifetime of the program and should be handled within pools.

Large collections of elements should be pooled as well referencing them as needed, one way to do this is to manage the pool with the disposable pattern where the Dispose method puts the pooled object back into the pool to be reused keeping in mind that you have to have full control over it.

When pre-allocating large objects what should follow is a forced collection of the GC calling `GC.Collect`so the large object can replace what was going to get rid as garbage and at the same time compacting the heap because of fragmentation. Once this objects are on the segment where they will live for the lifetime of the program they can be safely pooled and referenced from there as needed.

## Caching
When you want to keep around objects that are expensive to create Weak References become useful for caching them, this is something to consider when memory available is restricted like on mobile devices or when large objects are easy to create and there is no need to have them around if you are not using them