Skip to content

Day 10 GC and IDisposables

Kobi Hari edited this page Nov 12, 2020 · 1 revision

Day 10 - Memory Management and IDisposables

Projects:

Fun with Resources Some experiments with the GC and some fun things to do with disposables

Memory Management

  • We talked about 4 memory areas
    • Stack (per thread)
    • Heap
    • Static
    • Code
  • We talked about the Reachable Object Graph
    • Starts from the Stacks and Static
    • Walks through object references
    • Objects that are not reachable are marked for collection
  • We talked about when the GC Runs
    • Memory Allocation Failed
    • Application Shutdown
    • Manually running GC
  • We said that the GC Does the following:
    • Calculates the reachable object graph
    • Releases unreachable objects
    • Runs Defragmantation of memory
    • Updates references to objects that moved
  • GC is blocking, When the GC runs, all threads stop
  • We talked about GC Generations
    • The more times an object "survives" GC, the higher it's generation is, and it is assumed the it is more likely to survive the next GC
    • We can test generation using GC.GetGeneration
    • We can use GC.GetTotalMemory to get the size of the heap
  • We talked about Unmanaged Resources
    • The GC only frees the managed memory
    • There are other resources that are not managed (File streams, connections, and so on)
    • In order to handle unmanaged resources, you can write a destructor (~ method) which will be executed by the GC
  • Rules for writing destructors
    • You cannot manually call a destructor, only the GC may call it
    • You cannot pass parameters to the destructor and it has no return value (not even void)
    • You cannot overload desctructors
    • You cannot restrict access (public, protected, and so on)
    • You cannot define destructor to Value types, since they reside on the stack and are therefore not desctructed
    • Destcrutor of subclass runs before the destructor of the base class (opposite to constructor)
    • You should not touch any external objects (managed) when inside a finalizer
  • We talked a little about GC Settings and Heuristics
  • The CLR supports 2 types of garbase collectors
    • Server GC - Mostly suited for 4 processors
    • Workstation GC - Mostly suited for single processor, or 2 processors
  • Concurrent GC
    • Starting from .net 4.5, server garbage collection is concurrent.
    • Starting from .net 4.6.2, you can also configure if there is affinity between each processor and the heap, the heap count.
  • Configuring the GC
    • You can set the GC type (server or workstation)
    • you can enable and disable concurrent GC (for server GC)
    • you can configure heap processor affinity and the heap count (for server GC)

Disposables in .Net

  • References:
  • We talked about Motivation:
    • We have no control over when the destructor is called
    • The destructor slows down the GC which blocks the application
    • The order destructors are called is unpredictable
  • IDisposable is an interface for voluntary destruction
  • Usually, the destructor calls Dispose to make sure the object is disposed when it is cleaned
  • We Created an object that frees resources both on destructor and on Dispose
    • We observed a problem: we have freed the resources twice
    • We used GC.SuprressFinalize(this) on Dispose - this way the destructor will not run
    • Another option is to call Dispose from the Destructor and make sure dispose only really runs once.
  • We saw how to handle internal disposable objects
    • When we are disposing our object, we need to also dispose the internal object
    • But if the GC initiated the dispose, it is possible that the objects have already been destructed, so we cannot call any method on them
    • So we add a boolean parameter to dispose so that disposing while GC is done non recursively
  • Keep a boolean isDisposed to make sure we are not disposed twice
  • Throw ObjectDisposedException when running method after disposal
  • We talked about The using statement
    • Calls the Dispose method automatically when leaving the block
    • Uses variable scope to prevent access to disposed object
    • Any termination of the block (using return, throw, continue, break are all different ways to exit block) will cause Dispose to run

The Disposable Factory pattern

  • BaseDisposable
    • Support IsDisposed
    • throws ObjectDisposedException
    • supports destructor disposing
    • supports isDisposing parameter
    • Supports Disposing event (INotifyDisposable interface)
  • We created a Disposable.Call method that converts an action into disposable that calls the action on dispose
  • We Implemented a "DisposedBy" method that disposes one disposable when the opther disposable disposes
  • We create some Other Examples
    • Cool Examples
    • Create a disposable counter
    • Writing to the console with specific color
  • We used disposables to Create AsyncMutex
    • The mutex itself is a factory of "premission to access critical code"
    • The factory method returns a Task<IDisposable> where the IDisposable is a token that grants permission to access the critical code and disposes when the code completes
    • The mutex keeps a queue of unfinished tasks that await a token and makes sure there is only one such token alive at any point
    • The token itself is a disposable that runs the Release method when it is disposed.