C# variables are instantiated where the type is declared (eg string s;) and freed at the closing brace of the current scope:
// Operates with Q memory
void FantasyMethod() {
var o = new BigObject();
{
var temp = new BigObject();
Populate(temp); // Populates o1 with N megabytes of data
o = PerformSomeOperationsOn(temp); // Returns a BigObject of size M (M is close to N)
// Currently, M+N memory is occupied, we have Q-M-N free
}
// Let's tell the garbage collector to catch up
GC.Collect();
GC.WaitForPendingFinalizers();
// Currently, M memory is occupied
DoUsefulStuffWith(o); // This method can only work if at least Q-M-N/2 memory is free
}
One benefit of this is that I can free large variables before the function returns. In the above (trivial) block, I have husbanded my limited available memory by disposing a large variable as soon as it is no longer needed.
- Is the above correct?
- Is doing this a good idea (I am interested in arguments for and against, not personal opinion or preference)? Would extracting the naked brace block as a method use memory less efficiently? What if I don’t want to make a new method for readability reasons?
No. C# isn’t C++, objects don’t have destructors, and you are not guaranteed that an object will be reclaimed the moment it leaves its declaring scope and no valid references to it exist.
If you need that level of predictability then you shouldn’t be using a managed language, period. Techniques do exist which can help to alleviate memory pressure in C#, but they are not often needed and you will never get the level of control that a language like C or C++ will give you.
Per your edit:
GC.Collect will attempt to run a GC pass, it doesn’t guarantee it. GC.WaitForPendingFinalizers blocks until all objects which have been marked for finalization have run their finalizers.