I think there's a bit mess. Want to make it more clear in common understanding.
You can't manage time for GCollection.
GC-n occurs when: System has low physical memory + Memory that is used by allocated objects on the managed heap surpasses an acceptable threshold. This threshold is continuously adjusted as the process runs. + GC.Collect method is called. In almost all cases, you don’t have to call this method, because GC runs continuously. GC.Collect method is primarily used for unique situations and testing.
GC optimizing engine determines best time to perform a collection, based upon allocations being made.
Exact time when Finalizer executes is undefined. To ensure deterministic release of resources for instances of class, implement a Close() method or provide an IDisposable.Dispose implementation + The finalizers of two objects are not guaranteed to run in any specific order + Thread on which the finalizer runs is unspecified. For case someone forget to Dispose use Destructor
~ YourClass(){Dispose(false);}
is transformed into:
protected override void Finalize() { try { … cleanup…} finally { base.Finalize(); } }
YourClass : IDisposable
It's ("Finalizer") used to perform cleanup operations on unmanaged resources held by current object before object is destroyed by GC. Method is protected and therefore is accessible only through this class or through a derived class. By default (when use ~), GC automatically calls an object's finalizer before reclaiming its memory.
GC adds an entry for each instance of the type to an internal structure finalization queue - an internal data structure (Queue) controlled by GC. Finalization queue contains entries for all objects in managed heap whose finalization code must run before GC can reclaim their memory. When GC finds objects to be garbage, it scans Finalization Queue looking for pointers to these objects. If a pointer is found, it is removed from Finalization Queue and added to Freachable Queue. Object is no longer considered garbage and its memory is not reclaimed. At this point, GC has finished identifying garbage. Special runtime thread empties the Freachable Queue, executing each object's Finalize method. Normally when Freachable Queue is empty, this thread sleeps.
You need minimum 2 GCollections for objects with destructor (That's why in Dispose pattern GC.SuppressFinilise(this) is used - you say to GC that don't move object to Generation_1 or Generation_2, that memory might be reclaimed as GC meet destructor) + (that also means that objects with finalizers are moved minimum to Generation_1, that GC checks about 10 times rarely (than Generaation_0) that means that objects you don't need stay in memory longer)
Suggest to apply or
using(...)
that transforms into
try { … } finally { XX.Dispose();}
or implement correctly IDisposable interface using IntPtr structure for unmanaged resources (it works with different architecture (32 or 64)). Do not recommend to use SafeHandle (Interopservices) because it works only with Win32 architecture (good in SafeHandle is that you don't need to implement IDisposable as it inherits from CriticalFinalizerObject)
Classic implementation of IDisposable when you don't need to care if someone forget to Dispose object (for that case you have ~ destructor):
For base class
public MyClass() { this.reader = new TextReader(); }
public class A : IDisposable
{
bool disposed = false; // Flag: Has Dispose already been called?
private Component handle;
private IntPtr umResource;
public void Dispose() {
Dispose(true); GC.SuppressFinalize(this); }
protected virtual void Dispose(bool disposing) {
if (disposed) return;
if (disposing) { // Free managed resources
if (reader != null) reader.Dispose();
if (handle != null) handle.Close(); }
if (umResource != IntPtr.Zero) { // Free unmanaged resources
umResource = IntPtr.Zero; }
disposed = true; }
~A() { Dispose(false); } } // Only if we have real unmanaged resources
For derived class
public class B : A {
private bool disposed = false;
protected override void Dispose(bool disposing) {
if (disposed) return;
if (disposing) { ... } // To free any managed objects
// Free unmanaged resources
disposed = true;
base.Dispose(disposing)} }
disposing false – call comes from Finalizer; disposing true – from Dispose (from you)
Sorry, forgot to RESUME:
** Use GC.Collect to force the system TO TRY to reclaim the maximum amount of available memory. You can also point out to GC which generations you want it to check. BUT AS I WROTE IN THE BEGINING - YOU HAVE NO CONTROL, even if you use GC.Collect - that doesn't guarantee anything (GC may override your call, etc), but you can try and it wouldn't bring any problems **