De Garbage Collector in C#
Inleiding
C# is een object georiënteerde programmeertaal waarin objecten worden geïnstantieerd uit klassen. Voor elk object wordt geheugen gebruikt en een object zal op een gegeven moment niet meer nodig zijn. De geheugenruimte voor die niet meer gebruikte objecten wordt dan vrijgegeven en dat gebeurt door de Garbage Collector (GC). In deze post meer over de Garbage Collector (GC). We zullen het één en ander toelichten aan de hand van een voertuig van fictieve autofabrikant MGIM (Migraine Imperialist Motors Corporation Groupe).
Destructor
In een eerdere post hadden we het over constructors gehad. Een constructor is een methode dat automatisch wordt gestart bij de instantiatie van een object. De naam van de constructor is gelijk aan de naam van de klasse en als zodanig herkenbaar. Er bestaan naast constructors ook destructors (ook wel finalizers genoemd).
Een destructor wordt gestart door de Garbage Collector zodra een object niet meer nodig is en het gebruikte geheugen vrijgegeven kan worden. In een destructor kun je eventueel wat extra functionaliteiten opnemen die ervoor zorgen dat dingen alsnog “opgeruimd” worden voor zover dat nog niet is gedaan door het .NET Framework en het operating system.
Een Destructor heeft de naam van de klasse waarbij de naam vooraf wordt gegaan door een “~” (tilde). In het voorbeeld in deze post gaat het om een klasse “MGIM” en de naam van de destructor / finalizer is dan ook “~MGIM”:
// Destructor
~MGIM()
{
Console.WriteLine("** Begin Destructor **");
Console.WriteLine("Vrijgeven MGIM object.");
Console.WriteLine("Wis alle sporen dat we
gesjoemeld hebben.");
Console.WriteLine("** Einde Destructor ** \r\n");
}
Een destructor is bedoeld voor het doen opnemen van zaken die ervoor zorgen dat dingen alsnog “opgeruimd” worden voor zover dat nog niet is gebeurd door het .NET Framework en het Operating System, maar voor deze demo houden we het op wat Console.WriteLines zodat we kunnen zien wanneer de destructor wordt aangeroepen door de Garbage Collector (GC). We draaien het programma vanuit een Windows Command Prompt bestand (.cmd):
@echo off
C:\GC\bin\Debug\GC.exe
pause
zodat we kunnen zien wanneer de Garbage Collector in actie komt. De Garbage Collector roept de destructor aan en we zien de desbetreffende Console.WriteLines dan ook verschijnen nadat het programma heeft gedraaid en objecten en geheugenruimtes vrij worden gegeven door de GC. MGIM besluit in de destructor nog wat zaken op te nemen die ervoor zorgen dat de laatste sporen van haar milieugesjoemel gewist worden.
Het is uiteindelijk aan het besturingssysteem wanneer de GC iets gaat doen en de GC bepaalt wanneer de destructor aangeroepen wordt. Het kan best zo zijn dat het voor het besturingssysteem beter uitkomt om eerst alles even on hold te zetten waardoor de GC en eventuele destructors pas op een later tijdstip actief worden. Helaas voor MGIM dat de sporen van haar gesjoemel op die manier nog even kunnen blijven liggen met een grotere kans op ontdekking.
Slot
In deze post heb ik een destructor toegevoegd aan een klasse. Een destructor heeft de naam van de klasse waarbij de naam vooraf wordt gegaan door een “~” (tilde).
De console applicatie wordt vervolgens vanuit een Windows Command File gestart en we zien dat de destructor actief wordt nadat het programma heeft gedraaid en objecten worden opgeruimd en geheugen wordt vrijgegeven.
Een destructor is bedoeld voor het doen opnemen van zaken die ervoor zorgen dat dingen alsnog “opgeruimd” worden voor zover dat nog niet is gebeurd door het .NET Framework en het Operating System.
Hopelijk ben je met deze posting weer wat wijzer geworden en ik hoop je weer terug te zien in één van mijn volgende blog posts. Wil je weten wat ik nog meer over C# heb geschreven? Hit the C# button…
Voorbeeldprogramma
using System;
namespace GarbageCollector
{
public enum Kleur
{
Groen,
Paars,
Geel,
Oranje,
Rood,
Grijs
}
public class MGIM
{
public virtual string OverJeAuto(int KleurSticker)
{
string resultaat = "";
switch (KleurSticker)
{
case (int)Kleur.Groen:
resultaat =
"- de milieuvriendelijkste.";
break;
case (int)Kleur.Paars:
resultaat =
"- iets onder de norm, maar voldoet.";
break;
case (int)Kleur.Geel:
resultaat =
"- al wat ouder en iets minder schoon.";
break;
case (int)Kleur.Oranje:
resultaat =
"- tamelijk oud en relatief vervuilend.";
break;
case (int)Kleur.Rood:
resultaat =
"- zeer vervuilend!";
break;
case (int)Kleur.Grijs:
resultaat =
"- ultra vervuilend!!";
break;
default:
resultaat =
"- geen gegevens bekend.";
break;
}
return resultaat;
}
// Backing variables
private string _merk;
private int _milieusticker;
private string _vervuilingsgraad;
// Property Merk
public string Merk
{
get { return _merk; }
set { _merk = value; }
}
// Property MilieuSticker
public int MilieuSticker
{
get { return _milieusticker; }
set { _milieusticker = value; }
}
// Property Vervuilingsgraad
public string Vervuilingsgraad
{
get { return _vervuilingsgraad; }
}
// Constructor
public MGIM(string merk, int milieusticker)
{
_milieusticker = milieusticker;
_merk = merk;
_vervuilingsgraad =
OverJeAuto(milieusticker);
}
// Destructor
~MGIM()
{
Console.WriteLine(
"** Begin Destructor **");
Console.WriteLine(
"Vrijgeven MGIM object.");
Console.WriteLine(
"Wis alle sporen dat we
gesjoemeld hebben.");
Console.WriteLine(
"** Einde Destructor ** \r\n");
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(
"*** Begin programma ***\r\n");
MGIM mijnMGIM = new MGIM(
merk: "MGIM Migraine Imperialist
Motors Corporation Groupe",
milieusticker: (int)Kleur.Grijs);
// En we hebben..
Console.WriteLine(
"U bent de trotse
eigenaar van:");
Console.WriteLine(
"- Een {0}.", mijnMGIM.Merk);
Console.WriteLine(
"- En de mileustickerkleur van
uw auto is {0}.\r\n," +
(Kleur)mijnMGIM.MilieuSticker);
Console.WriteLine(
"Over de vervuilingsgraad
van uw auto:\r\n" +
"{0}\r\n",
mijnMGIM.Vervuilingsgraad);
Console.WriteLine(
"*** Einde programma ***\r\n");
}
}
}