[C#] Destructors en garbage collection

Pagina: 1
Acties:
  • 189 views sinds 30-01-2008
  • Reageer

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:37
Aargh, garbage collection.... :(

Ik ben bezig met het maken van een errorlogger. (Zie dit topic).

Ik heb dus een class Logger, die er als volgt uit ziet:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Logger
{
  private static Logger   _logger;

  private TextFileLogWriter _TextLogger;
  private DatabaseLogWriter _DbLogger;

  private LogWriter         _LogWriter;

  public Logger()
  {
    _TextLogger = new TextFileLogWriter();
    _DbLogger   = new DatabaseLogWriter();
  }

  static Logger()
  {
    _logger = new Logger();
  }

  public static void WriteLog (...)
  {
    _logger.PrepareLogger();
    _logger._LogWriter.WriteLog(...);
  }
}


WriteLog is dus een static method die ik in een applicatie als volgt kan
aanroepen:
code:
1
Logger.WriteLog(...);

Dit werkt perfect. Adhv de gespecifieerde argumenten gaat PrepareLogger maatregelen
treffen om de juiste LogWriter te gaan klaarzetten. Dan wordt de WriteLog method
aangeroepen van de betreffende LogWriter en wordt de error weggeschreven. Tot daar geen
probleem.

Echter, bij het afsluiten van de applicatie die de Logger.WriteLog method aanroept, wil
ik een aantal resources vrijgeven. Bv, het sluiten van de databank connectie of het
sluiten van de textfile naar waar errors weggeschreven worden.
Ik had gedacht om dit in de destructor te doen van de LogWriter classes:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
internal class DatabaseLogWriter
{
  ~DatabaseLogWriter()
  {
    this.EndLogging();
  }

  public override void EndLogging()
  {
    this.WriteLog("Logging ended");
    this._Conn.Close();

    base.EndLogging();
  }
}

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
internal class TextFileLogWriter()
{
  ~TextFileLogWriter()
  {
    this.EndLogging();
  }

  public override void EndLogging()
  {
    this.WriteLog("Logging ended");
    this._LogFile.Close();
    
    base.EndLogging();
  }
}


Nu stuit ik soms op het volgende probleem:
Ik heb een aantal errors gelogged in m'n applicatie en ik sluit de applicatie af.
De destructors van _TextLogger en _DbLogger worden aangeroepen en de EndLogging()
method wordt uitgevoerd.
Zoals je kunt zien wil ik dat die EndLogging() method nog een entry wegschrijft, zodat
ik kan weten wanneer het loggen gestopt werd.
Bij het wegschrijven van die informatie krijg ik echter soms volgende fouten:
An unhandled exception of type 'System.ObjectDisposedException' occurred in mscorlib.dll

Additional information: Cannot write to a closed TextWriter.
Bij het wegschrijven van de stop-informatie naar de TextFileLogger is m'n file blijkbaar
reeds gesloten. En dat terwijl de Close() method van die file toch enkel maar aangeroepen
wordt in EndLogging nadat ik die stop-informatie weggeschreven heb.

In andere gevallen krijg ik dan een dergelijke fout, maar dan bij de DatabaseLogWriter:
An unhandled exception of type 'System.InvalidOperationException' occurred in system.data.dll

Additional information: Handle is not initialized.
Nu denk ik dat die garbage collector er voor iets tussen zit, en ik zou dus graag willen weten
hoe ik nu m'n resources goed kan vrijgeven.
Ik heb al zitten denken om die 'stop-info' niet weg te schrijven. Ik zou dan gewoon in de
destructor van de DatabaseLogWriter de connectie sluiten en in de destructor van de FileLogWriter
de file sluiten. Dit heb ik reeds geprobeerd, en dat lukt blijkbaar probleemloos. Ik krijg dan nl. geen fouten bij het aanroepen van _Conn.Close en _LogFile.Close().

* whoami vind dat hij nogal redelijk veel topics opent de laatste tijd. :P
* whoami vind ook dat dit nogal een lap tekst is.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:37
[nohtml]
whoami schreef op 28 oktober 2002 @ 14:37:
Ik heb al zitten denken om die 'stop-info' niet weg te schrijven. Ik zou dan gewoon in de
destructor van de DatabaseLogWriter de connectie sluiten en in de destructor van de FileLogWriter
de file sluiten. Dit heb ik reeds geprobeerd, en dat lukt blijkbaar probleemloos. Ik krijg dan nl. geen fouten bij het aanroepen van _Conn.Close en _LogFile.Close().
Blijkbaar gaat er dan ook iets niet goed.
Als ik nl. de AutoFlush property van m'n StreamWriter niet op true zet, dan zou alle informatie naar de stream (de file) moeten weggeschreven worden als ik de close() method van die StreamWriter oproep.
Die close wordt dus in de destructor aangeroepen.
Ik heb dat dus eens geprobeerd, en ik zie dat de destructor aangeroepen wordt, geen fouten geeft, maar m'n file blijft leeg. Blijkbaar gaat er dan dus ook iets mis.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Feyd-Rautha
  • Registratie: November 2001
  • Laatst online: 02-08 23:34
* Feyd-Rautha gaat ook eens zijn steentje bijdragen :P

In verband met uw geclosede file:

code:
1
2
3
4
5
6
7
public override void EndLogging()
  {
    this.WriteLog("Logging ended");
    this._LogFile.Close();
    
    base.EndLogging();
  }


Je sluit dus eerst uw file (_LogFile.close(); ) en daarachter roept u de method endLogging van uw base-class terug op. Ik veronderstel dat die base-method ook schrijft, maar aangezien je je file al geclosed is, lukt dat niet. (of wordt er dan naar een andere file geschreven misschien ? )

I must not fear. Fear is the mind-killer. Fear is the little-death that brings total obliteration. I will face my fear. I will permit it to pass over me and through me. Where the fear has gone there will be nothing. Only I will remain.


Acties:
  • 0 Henk 'm!

  • Feyd-Rautha
  • Registratie: November 2001
  • Laatst online: 02-08 23:34
whoami schreef op 28 oktober 2002 @ 14:46:
[nohtml]
[...]

Blijkbaar gaat er dan ook iets niet goed.
Als ik nl. de AutoFlush property van m'n StreamWriter niet op true zet, dan zou alle informatie naar de stream (de file) moeten weggeschreven worden als ik de close() method van die StreamWriter oproep.
Die close wordt dus in de destructor aangeroepen.
Ik heb dat dus eens geprobeerd, en ik zie dat de destructor aangeroepen wordt, geen fouten geeft, maar m'n file blijft leeg. Blijkbaar gaat er dan dus ook iets mis.
Uw file blijft leeg omdat de gegevens nog niet geflushed zijn waarschijnlijk bij het closen van uw file. Uw autoClose property staat immers op false.

I must not fear. Fear is the mind-killer. Fear is the little-death that brings total obliteration. I will face my fear. I will permit it to pass over me and through me. Where the fear has gone there will be nothing. Only I will remain.


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:37
Neen, die EndLogging method van m'n base-class (LogWriter doet eigenlijk niets anders dan de property Started op false zetten.
Ik krijg de fout wel degelijk op de regel
code:
1
this.WriteLog("Logging ended")


Als ik daar ga in ga steppen, dan zie ik dat ik die fout in het geval van de DatabaseLogWriter krijg op de regel
code:
1
_cmdWrite.ExecSQL();

en in het geval van de TextFileLogWriter op de regel
code:
1
_LogFile.WriteLine (...);


de attributen _LogFile en _cmdWrite staan echter beiden niet op NULL.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:37
Feyd-Rautha schreef op 28 oktober 2002 @ 14:57:
[...]


Uw file blijft leeg omdat de gegevens nog niet geflushed zijn waarschijnlijk bij het closen van uw file. Uw autoClose property staat immers op false.


Je bedoelt de AutoFlush property?
De AutoFlush property gaat er voor gaan zorgen dat, als StreamWriter.WriteLine() opgeroepen wordt, de tekst direct naar de file wordt weggeschreven, zonder dat je daar zelf de Flush method moet voor gaan aanroepen.

De close method zou er wel moeten voor zorgen dat alle gegevens die zich nog in het buffer bevinden, geflushed worden naar de file:
You must call Close to ensure that all data is correctly written out to the underlying stream. Following a call to Close, any operations on the StreamWriter might raise exceptions.

Flushing the stream will not flush its underlying encoder unless you explicitly call Flush or Close

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:37
Vreemd, in het geval van de DatabaseLogWriter krijg ik dus de fout 'Handle is not initialized'.

Als ik ga gaan debuggen, zie ik dat _handle (attribuut van SqlCommand blijkbaar) op -1 staat. Als ik echter gewoon een error ga gaan loggen (en ik die fout dus niet krijg), dan staat die _handle ook op -1?
* whoami snapt het nu niet, of ik ben naar het verkeerde attribuut aan het kijken.

* whoami gaat ff checken wat de waarden precies zijn van StreamWriter in die situatie.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:37
Ik heb het nu zo:
Ik heb een static method bijgemaakt in m'n Logger class:
code:
1
2
3
4
5
6
7
8
9
10
11
public static void EndLogging()
{
  if( _logger._DbLogger.Started )
  {
    _logger._DbLogger.EndLogging();
  }
  if( _logger._TextLogger.Started )
  {
    _logger._TextLogger.EndLogging();
  }
}

Die method roep ik dan zelf op in m'n applicatie als ze afgesloten wordt. Dit werkt dan perfect. Alles wordt goed weggeschreven ed.
Maar toch had ik het graag gehad dat alles mooi afgesloten wordt zonder dat ik gebruik moet maken van zo'n extra method. En ik vraag me ook nog altijd af wat het probleem kan zijn met die destructors.

Waar zitten die C# goeroe's hier? :P

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23:05
Ik kan me voorstellen dat C# geen garanties doet over de volgorde waarin destructoren worden aangeroepen. Bij het afsluiten van een applicatie worden (in principe) alle destructoren van alle bestaande objecten aangeroepen. Als de API waarvan je gebruik maakt zelf ook objecten gebruikt, om de genoemde functies (entry schrijven, etc.) uit te voeren, dan kan het goed zijn dat een intern object al opgeruimd is wanneer jou destructor aan de beurt komt. Dan gaat het dus mis.

Dit is allemaal puur hypothetisch, trouwens, dus misschien klopt er niets van. Ik weet verder niet precies hoe een C# programma eruit ziet, maar in C++ zou je dit op kunnen lossen door je logger klasse in je main-functie aan te maken en op te ruimen, zodat de destructor in ieder geval voor de globale destructoren en de code buiten de main-functie uitgevoerd worden.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:37
Soultaker schreef op 28 oktober 2002 @ 19:58:
Ik kan me voorstellen dat C# geen garanties doet over de volgorde waarin destructoren worden aangeroepen. Bij het afsluiten van een applicatie worden (in principe) alle destructoren van alle bestaande objecten aangeroepen. Als de API waarvan je gebruik maakt zelf ook objecten gebruikt, om de genoemde functies (entry schrijven, etc.) uit te voeren, dan kan het goed zijn dat een intern object al opgeruimd is wanneer jou destructor aan de beurt komt. Dan gaat het dus mis.

Dit is allemaal puur hypothetisch, trouwens, dus misschien klopt er niets van. Ik weet verder niet precies hoe een C# programma eruit ziet, maar in C++ zou je dit op kunnen lossen door je logger klasse in je main-functie aan te maken en op te ruimen, zodat de destructor in ieder geval voor de globale destructoren en de code
buiten de main-functie uitgevoerd worden.


Ik vermoed eigenlijk dat het niet ligt bij de volgorde van de destructors. Als de destructor van één van m'n interne objecten aangeroepen wordt, dan zou dat object null moeten zijn. En dat is hier niet het geval.
Ik denk dat de aanroepen van de destructors wel op in de goede volgorde verlopen in .NET.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

Soultaker schreef op 28 oktober 2002 @ 19:58:
Dit is allemaal puur hypothetisch, trouwens, dus misschien klopt er niets van. Ik weet verder niet precies hoe een C# programma eruit ziet, maar in C++ zou je dit op kunnen lossen door je logger klasse in je main-functie aan te maken en op te ruimen, zodat de destructor in ieder geval voor de globale destructoren en de code buiten de main-functie uitgevoerd worden.
Of vergelijkbaar: een base-class definieren voor je eigen classes alwaar je een static private errorlogger subclass in frot met een protected interface. De logger wordt wordt dan pas geinstantieerd op het moment dat ie nodig is, en pas vernietigd nadat alle afgeleide classes zijn gemolesteerd. Deze truc is voor een logger-class wellicht overkill, maar ik gebruik 'm wel met succes voor memory-checking concepten.

[ Voor 0% gewijzigd door curry684 op 28-10-2002 23:00 . Reden: typo ]

Professionele website nodig?


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:37
curry684 schreef op 28 oktober 2002 @ 22:57:
[...]

Of vergelijkbaar: een base-class definieren voor je eigen classes alwaar je een static private errorlogger subclass in frot met een protected interface. De logger wordt wordt dan pas geinstantieerd op het moment dat ie nodig is, en pas vernietigd nadat alle afgeleide classes zijn gemolesteerd. Deze truc is voor een logger-class wellicht overkill, maar ik gebruik 'm wel met succes voor memory-checking concepten.


Dus zeg maar een class BaseLogger aanmaken met daarin een static BaseLogger.
En dan m'n Logger class inheriten van BaseLogger?

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class BaseLogger
{
   private static BaseLogger _logger;

   protected static BaseLogger_logger
   {
     get
     {
        return _logger;
     }
     set
     {
        _logger = value;
     }
   }
}

class Logger : BaseLogger
{
...
}

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

whoami schreef op 28 oktober 2002 @ 23:04:

[...]


Dus zeg maar een class BaseLogger aanmaken met daarin een static BaseLogger.
En dan m'n Logger class inheriten van BaseLogger?
Mmm het ging even over C++, anders had ik niet gereageerd :D

Ik doelde op een constructie als volgt:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MyBaseObject
{
public:
  ...

protected:
  void             LogError(const MyString &p_Description) const;
  void             LogWarning(const MyString &p_Description) const;
  void             LogInformation(const MyString &p_Description) const;

private:
  static class LogManager
    {
    public:
                  LogManager();
                 ~LogManager();
                  ... <specifieke implementatie> ...
    } m_LogManager;
};

En dan al je eigen classes afleiden van MyBaseObject. Op dat moment weet je zeker dat alleen je eigen classes de Log-functies kunnen gebruiken, de LogManager wordt op het correcte moment geinstantieerd, en wordt als laatste in de hele rits vernietigd.

Ik weet niet of deze aanpak mogelijk is in C#, en ik zou 'm zelf niet zo snel gebruiken voor een errorlogger (vind dit een te low-level constructie daarvoor), maar voor een niet al te grote app garandeert het een in ieder geval de correct volgordes.

Professionele website nodig?


Acties:
  • 0 Henk 'm!

Verwijderd

Even wat algemene opmerkingen over destructors en C#...
Ik kan me voorstellen dat C# geen garanties doet over de volgorde waarin destructoren worden aangeroepen.
Dit is idd een correcte aanname, maar in principe kun je er wel vanuit gaan dat de destructors in de juiste volgorde worden afgehandeld. Het probleem ligt meer in het feit dat je niet weet wanneer de Garbage Collector voorbij komt. Dat kan meteen na het aanroepen van de destructor zijn, maar ook veel later.

Dat nu is precies de reden dat in de literatuur en op .NET cursussen wordt afgeraden om destructors (a) te gebruiken en (b) als je ze gebruikt, er iig geen zaken in op te nemen als het sluiten van een database connectie of bestand. :7

Verder roept de destructor impliciet de Object.Finalize() methode aan op de base class van het betreffende object.

De Garbage Collector is te "forceren" door de GC.Collect() methode te gebruiken. Maar zelfs deze aanroep garandeert niet eens dat hij ook daadwerkelijk direct wordt aangeroepen.

Het idee van C# is (itt tot bv C++) dat je geen destructors meer hoeft te gebruiken, "omdat" de GC ooit wel een keer langs komt om netjes de boel op te ruimen. :) Voor beide aanpakken zijn uiteraard weer voor- en nadelen aan te dragen, maar dat is weer een heel andere discussie...

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:37
Verwijderd schreef op 29 oktober 2002 @ 10:06:

Dat nu is precies de reden dat in de literatuur en op .NET cursussen wordt afgeraden om destructors (a) te gebruiken en (b) als je ze gebruikt, er iig geen zaken in op te nemen als het sluiten van een database connectie of bestand. :7

en dat deed ik net....
Maar het was wel zo dat ik die fout kreeg bij het wegschrijven van informatie naar dat bestand in de destructor, niet in het sluiten ervan.
Maar goed, ik heb het nu zo:
Iedere keer er iets gelogged wordt, wordt het bestand geopend, informatie weggeschreven, bestand gesloten. Bij een databanklogger doe ik hetzelfde principe:
connectie openen, record inserten, connectie sluiten.

Ik weet niet of dat de 'preffered' manier is, omdat ik dan nogal veel de connectie/bestand ga openen en sluiten. Dat zal wel een performance-loss met zich meebrengen, aan de andere kant hou ik de resources niet langer bezet dan nodig.
Ik dacht zelfs dat het in .NET gepropageerd werd om een databank connectie zo kort mogelijk open te houden. Dus iedere keer je databank acces moet doen, de connectie openen. Gegevens erin of eruit, connectie terug sluiten.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

Verwijderd

Zoals je 't nu opgelost hebt, is 't idd wel de 'preffered' manier... :) Maar je hebt wel een punt natuurlijk: veel roundtrips en dus performance-loss.
Voor een (error)log-component zou dat volgens mij nog wel acceptabel kunnen zijn, omdat die niet zo vaak aangeroepen wordt. ;)

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23:05
Uit de eerste helft van Yarvieh's (interessante) documentje maak ik op, dat de C# ontwikkelaars juist wel graag deterministische en onmiddelijke garbage collection wilden. Onder andere dit voorbeeld wordt gegeven:
code:
1
2
3
        File f = new File("c:\foo.txt");
        byte[] b = f.Read();
        File.Delete("c:\foo.txt");

Waarbij het bestandsobject direkt na de Read() aanroep opgeruimd zou moeten worden (zodat 't niet in gebruik is wanneer 'ie verwijderd wordt).

Ik heb het artikel helaas niet uitgelezen, maar het is toch jammer dat dit schijnbaar niet gelukt is, als ik Puckly mag geloven.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:37
Puckly mag je geloven. Het is onmogelijk om precies vast te stellen wanneer de Garbage Collector langs komt en wanneer geheugen en resources dus vrijgegeven worden.
The .NET Framework's garbage collector manages the allocation and release of memory for your application. Each time you use the new operator to create an object, the runtime allocates memory for the object from the managed heap. As long as address space is available in the managed heap, the runtime continues to allocate space for new objects. However, memory is not infinite. Eventually the garbage collector must perform a collection in order to free some memory. The garbage collector's optimizing engine determines the best time to perform a collection, based upon the allocations being made. When the garbage collector performs a collection, it checks for objects in the managed heap that are no longer being used by the application and performs the necessary operations to reclaim their memory.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

Soultaker schreef op 29 oktober 2002 @ 10:53:
Uit de eerste helft van Yarvieh's (interessante) documentje maak ik op, dat de C# ontwikkelaars juist wel graag deterministische en onmiddelijke garbage collection wilden.
Dit is een contradictio in terminis... deterministische garbage collection is in strijd met zichzelf. Garbage collection is het concept waarbij er (theoretisch) een low-priority thread rondwaart die om de tijd alle gealloceerde objecten controleert op hun referencecount, en indien niet langer gebruikt wegflikkert. Met deterministisch bedoel je neem ik aan dat het exacte moment van destructie te voorspellen is, en daarvoor heb je helaas stack-unwind mechanismes nodig zoals de smart pointer.

Stel je eens de hilariteit voor toen een MS-representative bij een C#-seminar in een zaal vol C++ developers met het schaamrood op de kaken moest bekennen dat de C# garbage collector niet eens garandeerde dat het object OOIT werd gedestruct... gelukkig kwam er meteen een collega het podium opsnellen die toevoegde dat dit in de laatste specificatie wel het geval was. Helaas moest ook hij er aan toevoegen dat dit op z'n tijd nog wel eens een half uur kon gebeuren nadat het programma zelf al afgelopen was :z

Dit was 2 jaar geleden op de MS Developer Days, en oh oh wat heb ook ik smakelijk gelachen :)

De mooiste functie van de Garbage Collector is imho GC.Disable() :Y)

Professionele website nodig?


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:37
curry684:
code:
1
unsafe{}

is iets voor jou. :Y)

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • skiwi
  • Registratie: Februari 2001
  • Laatst online: 21-09 13:28
Misschien een beetje off topic:

Ik heb ook problemen gehad met de timing van de Garbage Collector. Ik heb een Windows Service applicatie in C# geschreven die via een WebService een SQL server database benaderde. Ik had het probleem dat ik de windows service niet uit de services list verwijderd kreeg. Dit kwam (volgens mij) omdat de verbinding naar de Webservice niet netjes werd opgeruimd. Na een paar dagen zoeken en een paar aspirientjes voor de hoofdpijn heb ik (per ongeluk) de oplossing gevonden: het opruimen van de achtergelaten troep door middel van een Dispose(). Dit heb ik in mijn service toegepast op elke nieuwe thread die ik aanmaak.

Bij C++ had je new() en delete(). Bij C# heb je geen delete() want de Garabage Collector zou dat allemaal voor je doen. Nou, niet helemaal dus. Het aanroepen van dispose() heeft bij mij een heleboel problemen opgelost.

Dispose:
Releases all resources used by the component

Calling Dispose allows the resources used by the Component to be reallocated for other purposes. For more information about Dispose, see Cleaning Up Unmanaged Resources.
Ik weet dus ook niet zeker of dit DE oplossing is maar het werkt bij mij perfect!

Zoals ik al zei: het is niet helemaal van belang op jou probleem maar misschien kan iemand anders er wat mee. Scheelt weer een boel ergenins tijdens het zoeken naar dit soort timing problemen.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:37
[nohtml]
skiwi schreef op 29 oktober 2002 @ 11:57:
het opruimen van de achtergelaten troep door middel van een Dispose(). Dit heb ik in mijn service toegepast op elke nieuwe thread die ik aanmaak.

Bij C++ had je new() en delete(). Bij C# heb je geen delete() want de Garabage Collector zou dat allemaal voor je doen. Nou, niet helemaal dus. Het aanroepen van dispose() heeft bij mij een heleboel problemen opgelost.
Ik kan het nog eens proberen, maar het aanroepen van een destructor zorgt er eigenlijk voor dat die Dispose method ook aangeroepen wordt. Ik denk dus dat het niet echt soelaas zal brengen.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

whoami schreef op 29 oktober 2002 @ 11:49:
curry684:
code:
1
unsafe{}

is iets voor jou. :Y)
Klopt, dat was het tweede punt van enorme hilariteit tijdens die seminar :D

Eerst krijg je een stuk of 12 hoofdstukken over de enorme type-safety van deze sublieme taal waarin je geen gekke dingen per ongeluk kunt doen en direct in geheugen modderen en zo, en vervolgens begon die man dus (terughoudend na z'n eerdere ervaringen over de GC) aan het hoofdstuk 'Unsafe Code'. En idd, de zaal lag weer meerdere keren plat :Y)

Ik zeg eerlijk: C# is een mooie taal die welzeker een hoop toekomst heeft (al is het alleen maar omdat de MS-marketing-machine er zo hard op ramt), maar het barst hier en daar ook wel van de gemiste kansen jammer genoeg. De 'unsafe' statement had er echt nooit in mogen komen, vergelijkbaar met 'goto' in C++. Als je zonodig low-level hardpointered chopwerk in C# moet doen roep je maar lekker een C++ component aan, het hele idee achter .NET is tenslotte dat je ieder component in de meest geschikte taal kunt implementeren waarna ze probleemloos samenwerken.

Professionele website nodig?


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:37
curry684 schreef op 29 oktober 2002 @ 12:09:
[...]
het hele idee achter .NET is tenslotte dat je ieder component in de meest geschikte taal kunt implementeren waarna ze probleemloos samenwerken.


Idd, maar dat moet dan wel in talen zijn die .NET ondersteunen. Als jij die component in VC++6 of in VC++.NET (mbhv unsafe code dan wel) schrijft, dan is die component niet meer CLR-managed.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

whoami schreef op 29 oktober 2002 @ 12:11:

[...]

Idd, maar dat moet dan wel in talen zijn die .NET ondersteunen. Als jij die component in VC++6 of in VC++.NET (mbhv unsafe code dan wel) schrijft, dan is die component niet meer CLR-managed.
Het probleem met een blokje unsafe in C# zit 'm er vooral in dat de hele applicatie erdoor een vlaggetje 'unsafe' krijgt als gevolg waarvan remote installers in de toekomst (Longhorn?) een waarschuwing geven of wellicht de app compleet weigeren. Ik mag echter hopen dat een managed VC++.NET app nog steeds gebruik van pointers toestaat om snelle code mee te schrijven, anders is het hele nut van C++ binnen .NET eigenlijk weg.

* curry684 heeft overigens nog niets gedaan met of gehoord over de 'unsafe' elementen van VC++.NET code... kan misschien fout zitten :Y)

Professionele website nodig?


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:37
curry684 schreef op 29 oktober 2002 @ 12:32:
[...]

Het probleem met een blokje unsafe in C# zit 'm er vooral in dat de hele applicatie erdoor een vlaggetje 'unsafe' krijgt als gevolg waarvan remote installers in de toekomst (Longhorn?) een waarschuwing geven of wellicht de app compleet weigeren. Ik mag echter hopen dat een managed VC++.NET app nog steeds gebruik van pointers toestaat om snelle code mee te schrijven, anders is het hele nut van C++ binnen .NET eigenlijk weg.

* curry684 heeft overigens nog niets gedaan met of gehoord over de 'unsafe' elementen van VC++.NET code... kan misschien fout zitten :Y)


Ik denk niet dat een 'unsafe' applicatie zal geweigerd worden door remote installers. Unsafe wil gewoon zeggen dat de applicatie niet door de CLR gemanaged wordt, en dus eigenlijk buiten het .NET framework draait.
AFAIK laat een managed VC++.NET applicatie het gebruik van pointers niet toe. Als je nl. pointers wilt gebruiken, moet je dat binnen het unsafe{} blok doen en heb je dus geen managed code meer. (In C# is dat in ieder geval zo, dus ik veronderstel dat het in VC++.NET niet anders is).

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23:05
curry684 schreef op 29 oktober 2002 @ 11:45:
Dit is een contradictio in terminis... deterministische garbage collection is in strijd met zichzelf.
Je hebt gelijk; ik had moeten zeggen "het opruimen van gealloceerde resources" in algemene zin en niet zozeer de specifieke implementatie van een garbage collector.
Pagina: 1