C# One-Pager
Introduction
This is in a question-answer format.
If you use a spaced repetition learning software like Anki, you can enter them into it or import them:- Anki package(apkg) and Anki package(txt)
This post will constantly be updated. Check the latest updates in the Updates section.
Memory Management
-
What are the problems with a Mark and Sweep Garbage Collector?
-
A mark and sweep GC has to mark all live objects on the heap during each collection cycle.
-
This can lead to long program freezes while the collection is running
-
Also: repeatedly marking the same objects over and over in each cycle is very inefficient.
-
-
How does a Generational Garbage Collector help reduce the problems of a Mark and Sweep Garbage Collector?
-
Generations help to reduce the number of objects in gen 0.
-
Gen 1 and Gen 2 are collected much less frequently.
-
The GC assumes that any object that reaches gen2 must be a long living object that does not need to be checked very often.
-
-
What are the Implicit assumptions that the garbage collector operates on?
-
Objects are either short-lived or long-lived.
-
Short-lived objects will be allocated and discarded within a single collection cycle.
-
Objects that survive two collection cycles are long-lived.
-
90% of all small objects are short-lived.
-
All large objects (85K+) are long-lived.
-
-
Which objects remain in the Gen0 list after every garbage collection cycle?
Gen0 is completely cleared i.e. empty.
-
When optimizing code for GC, what are the two considerations you must look for with regards to object size and lifetime?
-
Avoid large short-lived objects
-
Avoid small long-lived objects
-
-
If you have a large short-lived object, what is the one optimization you can try?
If you have a large object like say a db connection and for some reason it is short-lived then one optimization that you can use to convert it to a long-lived object is to to pool it in an object pool and reuse it the next time.
-
Should a finalizer process other referenced objects?
A finalizer must only process its own object and never other referenced objects.
-
You have some referenced objects in your class, will you process them in a finalizer?
No. A finalizer must only process its own object and never other referenced objects.
-
In what order are objects finalized?
You cannot make any assumptions about the order in which your objects will be finalized.
-
Why must you never use a referenced object in finalizer?
You should never try to use a referenced object in your finalizer, because it might already be finalized.
-
In which generation are finalizers always executed?
Finalizers always execute in gen1. So, the lifetime of your object will span 2 generations i.e 2 collection cycles.
-
Are finalizers guaranteed to be called?
Finalizers are not guaranteed to be called.
-
What happens to objects that have not been finalized yet when the host process exits?
If the host process exits, anything remaining in the finalization queue after 4 seconds is discarded.
-
What are finalizers?
Finalizers are class methods that are called when objects are about to be cleaned up by the garbage collector.
-
Why is it bad to have many short-lived objects with finalizers?
Many small short-lived objects with finalizers are bad, because the finalizer extends their lifetime into gen1.
-
Is it a good idea to release scarce resources in a finalizer?
No because the time interval between the object creation and the finalizer running could be used. The resource could be kept allocated for a long time. Finalizer only runs in gen1. Dispose disposes in gen 0.
-
Why is it better to use the Dispose method instead of a finalizer to discard scarce resources?
-
The time interval between the object creation and the finalizer running could be used.
-
Finalizer only runs in gen1. Dispose disposes in gen 0.
-
-
What does the dispose pattern provide?
The dispose pattern provides a method for explicitly releasing scarce resources.
-
Things to keep in mind while optimizing your code
-
Avoid boxing and unboxing.
-
Do not concatenate strings
-
Use structs instead of classes.
-
Always pre-size collections.
-
-
What is boxing and unboxing?
Boxing and Unboxing is a process that lets you use value types and reference types interchangeably in your code.
-
What does a boxing operation do?
It converts a value type to a reference type.
-
Where is the output object of a boxing operation stored - stack or heap?
Each boxing operation creates one new object on the heap.
-
Which object is greater in size - a boxed object or its original value type?
A boxed object occupies more memory than the original value type.
-
Why is it advisable to always pre-size collections?
Every collection and list in .NET starts out with a certain default capacity, and when it runs out of space it will create a new list of twice the size and copy everything over.
-
What are the three standard rules of object disposal?
-
After an object has been disposed, it cannot be reactivated.
-
Calling an object’s Dispose method repeatedly causes no error.
-
A container object automatically disposes its child objects.
-
-
Into how many generation does a GC divy its objects?
The GC divides objects into three generations.
-
What type of objects does the GC collect more frequently?
Gen0 and Gen1
-
What is a root?
A root is something that keeps an object alive.
-
When is an object eligible for garbage collection?
When an object is not directly or indirectly referenced by a root, it is eligible for garbage collection.
-
What are the three types of roots?
-
A local variable/parameter in an executing method.
-
A static variable.
-
An object on the queue that stores objects ready for finalization.
-
-
When does a finalizer execute?
Just before an object is released from memory.
-
What are the various phases of a garbage collector?
-
Objects without finalizers are immediately deleted.
-
Objects with pending finalizers are put on a queue.
-
Garbage collection is complete and the program continues executing.
-
A finalizer thread starts running in parallel.
-
The finalizer methods of the objects in the finalizer queue are executed.
-
The objects are then dequeued.
-
The dequeued objects will be deleted in the next collection.
-
-
What sort of GC does the standard CLR use?
It uses a generational mark and compact GC.
-
When does the CLR initiate a garbage collection?
When the new keyword is called and a memory threshold has been reached.
-
Can you manually initiate a Garbage Collection?
Yes by calling System.GC.Collect.
-
Can all threads be frozen during a GC?
Yes all threads can be frozen.
-
What does the GC do in the marking step?
It marks all objects that can be reached from the root.
-
What does the GC do in the compact phase?
The remaining objects are shifted to the start of the heap(compacted).
-
What is the purpose of the compaction phase?
-
New objects can easily be allocated at the end of the heap.
-
It prevents memory fragmentation.
-
New objects can easily be allocated at the end of the heap.
-
-
Why should we keep large objects on the LOH and not in Gen0 or Gen1 or Gen2 collections?
-
As these are large objects, compacting them is an expensive operation making Gen0, Gen1 and Gen2 collections slower.
-
Also as they are large objects, they fill up the memory threshold faster making the GC collect more often.
-
For these reasons, it is better to move them to another heap like the LOH.
-
-
Why is LOH not subject to compaction?
Because moving large objects during garbage collection would be expensive.
-
What are the implications of an LOH not being compacted?
Slower Allocation and Fragmentation
-
How can you manually instruct the GC to compact the LOH?
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
-
In what generation of the GC is the LOH stored?
The LOH is non generational.
-
What are the 2 garbage collection modes provided by the .NET CLR?
Workstation and server are the two garbage collection modes provided by the .NET CLR.
-
How can you switch to Server GC mode?
<PropertyGroup><ServerGarbageCollection>true</ServerGarbageCollection></PropertyGroup>
-
What is the difference between the Server GC and the Workstation GC?
Server GC - allocates a separate heap and a separate GC to each core.
-
In what type of systems is a Server GC only available on?
On multicore systems.
-
What is the background GC feature offered by the CLR?
The GC must freeze execution threads during a collection. A background gc minimizes these freezes.
-
How can you enable Background collection?
<PropertyGroup> <ConcurrentGarbageCollection>false</ConcurrentGarbageCollection> </PropertyGroup>
-
Can you manually start garbage collections for only a specific generation?
Yes you pass an int value to
GC.Collect
representing the generation to collect. -
What is the most common reason for memory leaks in a managed language?
Event Handlers.
-
What is the other most common reason for memory leaks in a managed language?
System.Timers
-
How can you manually obtain the current memory consumption of a program’s objects?
GC.GetTotalMemory(true)
. It returns a 'long'.
Nullability
-
What are the three operators in C# that operate on null references?
-
Null-Coalescing Operator (??)
-
Null-Coalescing Assignment Operator (??=)
-
Null-Conditional Operator (?.)
-
-
Explain how the null-coalescing(??) operator works?
-
If the lefthand expression is non-null, then the righthand expression is never evaluated.
-
If the lefthand expression is null, then the righthand expression is evaluated.
-
-
How does the Null-Coalescing Assignment Operator(??=) work?
If the operand to the left is null, the right operand is assigned to the left operand.
-
What feature does the Null-Conditional operator(?.) provide?
If the operator on the left is null, the expression evaluates to null instead of throwing a NullReferenceException.
-
Does null-conditional operator also work with indexers?
Yes.
-
Explain the feature Nullable Reference Types?
Nullable Reference Types make reference types non-nullable. By default, Reference types are nullable.
-
How can you enable the Nullable Reference Type feature in a C# project?
You can enable this feature by adding
<Nullable>enable<Nullable>
to the .csproj file. -
What happens when you enable the Nullable Reference Type feature?
-
All reference types are treated as nullable.
-
The compiler generates a warning if a line of code risks throwing a NullReferenceException.
-
-
When would you use a null-forgiving operator(!)?
If you know for sure that an object cannot be null, you can use the null forgiving(!) operator at the end of the object to remove the nullable reference type warning.
-
Explain the term - nullable annotation context?
All reference types are treated as non-nullable.
-
How do you enable nullable annotation context in a C# file?
#nullable enable annotations
-
What does enabling the nullable warning context do?
Generates a warning when a line of code risks throwing a
NullReferenceException
. -
How do you enable nullable warning context in a
C#`
file?#nullable enable warnings
-
Why would you enable only the Nullable Annotation Context?
It is a good first step towards introducing nullable reference types to a legacy codebase.
Value Types
-
What are structs?
Structs are value types
-
Things to remember about structs:-
-
Assigning structs copies the value of all internal fields.
-
Structs can implement interfaces but cannot inherit.
-
Structs cannot have instance field intializers.
-
Structs cannot have a parameterless constructor.
-
Structs cannot have finalizers.
-
-
Use cases for structs:-
-
Use structs when the data you are storing represents a single value.
-
Use structs if your data size is very small (24 bytes or less) and you are going to create thousands or millions of instances.
-
Use structs if your data is immutable.
-
Use structs if your data will not have to be boxed frequently
-
Updates
-
11-Jun-2023 - Added Nullability section, Value Types section and new questions to the Memory Management Section. Anki package(apkg) and Anki package(txt)
-
10-Jun-2023 - Added the first post Anki package(apkg) and Anki package(txt)