[.net] resources release met dispose()

Pagina: 1
Acties:

Onderwerpen


  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
Beste mensen,

Ik heb een vraagje over disposible objects.

Ik heb een situatie, waarin ik met een eigen class een disposible object gebruik. Echter deze wordt gedefineerd als een class var, en wordt in verschillende methoden in die class gebruikt.

Nu wil ik die natuurlijk netjes disposen als mijn eigen class opgeruimd wordt.

Ik vroeg mij alleen af of ik daarvoor mijn eigen class ook disposible moet maken of dat dit ook anders kan.

voorbeeld code (uit mijn hoofd)
C#:
1
2
3
4
5
6
7
8
9
10
11
class Eigen {
  OracleCommand command;

  public Eigen(string connStr) {
    command = new OracleCommand("SELECT 1 FROM DUAL", connStr)
  }

  public bool DoeIets() {
    return (command.ExecuteScalar() > 0);
  }
}



Hoe ik het nu heb gemaakt:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Eigen : IDisposable {
  OracleCommand command;

  public Eigen(string connStr) {
    command = new OracleCommand("SELECT 1 FROM DUAL", connStr)
  }

  public bool DoeIets() {
    return (command.ExecuteScalar() > 0);
  }

  public void Dispose() {
    if (command != null)
      command.Dispose();
  }
}

[ Voor 20% gewijzigd door BasieP op 23-08-2012 08:43 ]

This message was sent on 100% recyclable electrons.


  • beany
  • Registratie: Juni 2001
  • Laatst online: 17-09 13:56

beany

Meeheheheheh

Wat bedoel je met 'class var' ??

En als het om OracleCommand gaat, die kan je toch gewoon disposen in je Dispose methode?

Schaamteloos gejat via de eerste google search hit( MSDN: Implementing a Dispose Method ):
C#:
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
    public void Dispose() 
    {
        Dispose(true);

        // Use SupressFinalize in case a subclass 
        // of this type implements a finalizer.
        GC.SuppressFinalize(this);      
    }

    protected virtual void Dispose(bool disposing)
    {
        // If you need thread safety, use a lock around these  
        // operations, as well as in your methods that use the resource. 
        if (!_disposed)
        {
            if (disposing) {
                if (_resource != null)
                    _resource.Dispose();
            }

            // Indicate that the instance has been disposed.
            _resource = null;
            _disposed = true;   
        }
    }

[ Voor 81% gewijzigd door beany op 23-08-2012 08:48 ]

Dagelijkse stats bronnen: https://x.com/GeneralStaffUA en https://www.facebook.com/GeneralStaff.ua


  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
beany schreef op donderdag 23 augustus 2012 @ 08:45:
Wat bedoel je met 'class var' ??

En als het om OracleCommand gaat, die kan je toch gewoon disposen in je Dispose methode?
...
knip
...
Ik weet hoe je hem disposible maakt, en ik weet dat een Oracle command disposible is.

Mijn vraag was:
Ik vroeg mij alleen af of ik daarvoor mijn eigen class ook disposible moet maken of dat dit ook anders kan.
Over die class var.

Het disposible object (in mijn voorbeeld een OracleCommand) is dus een class member. Zodoende is een using block (de makkelijkste methode) dus niet haalbaar.

Nu kan ik ook een destructor gaan defineren voor mijn eigen class en daarin de .Dispose() van mijn members aanroepen, maar ik vroeg me af of hier best practices voor waren.

voor zover kan ik 2 oplossingen bedenken
  1. IDisposible implementeren, zodat de aanroeper van mijn eigen class die moet disposen (probleem verplaatsen)
  2. Destructor defineren, en daarin de dispose aanroepen

This message was sent on 100% recyclable electrons.


  • beany
  • Registratie: Juni 2001
  • Laatst online: 17-09 13:56

beany

Meeheheheheh

Ik heb nog nooit een destructor gebruikt voor een eigen class, en volgens mij is dat ook not-done in c#. De Dispose methodiek is de aangewezen manier om disposables op te ruimen.

Dagelijkse stats bronnen: https://x.com/GeneralStaffUA en https://www.facebook.com/GeneralStaff.ua


  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
beany schreef op donderdag 23 augustus 2012 @ 09:58:
Ik heb nog nooit een destructor gebruikt voor een eigen class, en volgens mij is dat ook not-done in c#. De Dispose methodiek is de aangewezen manier om disposables op te ruimen.
Klopt. De garbage collector in C# heeft ook kennis van de IDisposable interface aan boord. Voor objecten die IDisposable implementeren, roept de collector eerst nog Dispose aan alvorens zijn werk te doen. Dat is dan ook één van de redenen waarom je binnen een Dispose method altijd moet controleren of deze al eerder aangeroepen is.

(Je kunt trouwens nog wel meer coole dingen met IDisposable doen, zoals objecten die automatisch terug naar een resource pool gestuurd worden voor hergebruik.)

  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
gewoon IDisposable implementeren dus

This message was sent on 100% recyclable electrons.


  • boe2
  • Registratie: November 2002
  • Niet online

boe2

'-')/

R4gnax schreef op donderdag 23 augustus 2012 @ 10:56:
[...] De garbage collector in C# heeft ook kennis van de IDisposable interface aan boord. Voor objecten die IDisposable implementeren, roept de collector eerst nog Dispose aan alvorens zijn werk te doen.
Dit klopt niet: De garbage collector zal nooit Dispose aanroepen. Het zal wel destructors uitvoeren, maar dit wordt inderdaad afgeraden om te implementeren in .NET.
IDisposable is iets wat je zelf aanroept, dan wel via try..finally, ofwel via de "using" statement (of je roept gewoon zelf Dispose() aan).

I don't blame you. Ik ben er ook lang van overtuigd geweest dat de GC wel automatisch het nodige ging doen op IDisposable classes, tot ik ooit het geheugenverbruik van een app grondig onder de loep moest nemen en mijn Dispose methods fijn genegeerd werden.

'Multiple exclamation marks,' he went on, shaking his head, 'are a sure sign of a diseased mind.' - Pratchett.


  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Het hele idee achter 'Disposable' is juist dat het iets is wat de programmeur voor zijn rekening moet nemen omdat het niet iets is wat de GC 'automatisch' kan doen. Als je een disposable gebruikt en die niet meteen weer kan disposen is de class zelf disposable maken de aangewezen manier.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

beany schreef op donderdag 23 augustus 2012 @ 09:58:
Ik heb nog nooit een destructor gebruikt voor een eigen class, en volgens mij is dat ook not-done in c#.
Als je class unmanaged resources managed dan zul je toch echt een destructor moeten implementeren.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
Stop het in de Destructor (dan gebeurt het sowieso maar het gebeurt pas na 2 iteraties van de garbage collector voordat het object echt opgeruimd is). Is de class die deze disposable variable als member heeft zelf ook een member van een class? Als dat niet zo is kun je toch using gebruiken met IDisposable maar dan 1 stapje omhoog. Of je moet manueel Dispose() aanroepen, dan wordt het eerder opgeruimd.
When you are using unmanaged resources such as handles and database connections, you should ensure that they are held for the minimum amount of time, using the principle of acquire late and release early. In C++ releasing the resources is typically done in the destructor, which is deterministically run at the point where the object is deleted. The .NET runtime, however, uses a garbage collector (GC) to clean up and reclaim the memory used by objects that are no longer reachable; as this runs on a periodic basis it means that the point at which your object is cleaned up is nondeterministic. The consequence of this is that destructors do not exist for managed objects as there is no deterministic place to run them.

Instead of destructors, C# has finalizers which are implemented by overriding the Finalize method defined on the base Object class (though C# somewhat confusingly uses the C++ destructor syntax ~Object for this). If an object overrides the Finalize method then rather than being collected by the GC when it is out of scope, the GC places it on a finalizer queue. In the next GC cycle all finalizers on the queue are run (on a single thread in the current implementation) and the memory from the finalized objects reclaimed. It's fairly obvious from this why you don't want to do clean up in a finalizer: it takes two GC cycles to collect the object instead of one and there is a single thread where all finalizers are run while every other thread is suspended, so it's going to hurt performance.

So if you don't have destructors, and you don't want to leave the cleanup to the finalizer, then the only option is to manually, deterministically, clean up the object. Enter the IDisposable interface which provides a standard for supporting this functionality and defines a single method, Dispose, where you put in the cleanup logic for the object. When used within a finally block, this interface provides equivalent functionality to destructors. The reason for finally blocks in code is primarily to support the IDisposable interface; this is why C++ uses simply try/except as there is no need for a finally block with destructors.

[ Voor 9% gewijzigd door roy-t op 24-08-2012 12:06 . Reden: Edit ivm feedback .oisyn ]

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-09 22:43
Begrijp ik het goed dat je in .NET geen fatsoenlijke manier hebt om resources die in een object worden beheerd gegarandeerd op te ruimen? IDisposable werkt alleen icm een using/manuele aanroep door de gebruiker van het object die dat kan 'vergeten', en de 'finalizer' wordt pas na 2 GC runs aangeroepen.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
farlane schreef op vrijdag 24 augustus 2012 @ 09:50:
Begrijp ik het goed dat je in .NET geen fatsoenlijke manier hebt om resources die in een object worden beheerd gegarandeerd op te ruimen? IDisposable werkt alleen icm een using/manuele aanroep door de gebruiker van het object die dat kan 'vergeten', en de 'finalizer' wordt pas na 2 GC runs aangeroepen.
Als dat zo'n enorm issue is moet je het aan de applicatiebouwer overlaten om z'n zooi op te ruimen en niet aan het framework.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Infinitive
  • Registratie: Maart 2001
  • Laatst online: 25-09-2023
farlane schreef op vrijdag 24 augustus 2012 @ 09:50:
Begrijp ik het goed dat je in .NET geen fatsoenlijke manier hebt om resources die in een object worden beheerd gegarandeerd op te ruimen? IDisposable werkt alleen icm een using/manuele aanroep door de gebruiker van het object die dat kan 'vergeten', en de 'finalizer' wordt pas na 2 GC runs aangeroepen.
Wat noem je gegarandeerd? Het typische patroon is dat je IDisposable implementeert, waarmee je kan garanderen (bijv. met behulp van using-syntax) dat Dispose aangeroepen wordt. Aangeraden wordt om een finalizer te implementeren die ook Dispose aanroept, zodat uiteindelijk Dispose toch aangeroepen wordt wanneer een programmeur dat vergeet. Alleen, wanneer precies weet je niet. Ik verwacht dat er een garantie is dat bij het termineren van je programma alle finalizers aangeroepen worden (?) en je kan in de praktijk verwachten dat uiteindelijk er wel een keer een garbage collectieronde komt.

Overigens wordt er aangeraden om in Dispose de GC-methode suppressFinalize aan te roepen om de finalizer-overhead te voorkomen in het doorgaanse scenario.

putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

roy-t schreef op vrijdag 24 augustus 2012 @ 08:01:
Je kunt het in de Destructor [..] doen maar dan kost het wel 2 iteraties van de garbage collector voordat het object echt is opgeruimd.
Nee, je moet het in de destructor doen. Van Dispose is niet gegarandeerd dat ie wordt aangeroepen. Uiteraard kun je het beste óók IDisposable implementeren zodat je ze al eerder op kunt ruimen, maar als je het niet in de destructor doet en niemand roemt Dispose() aan dan leak je resources. Vandaar dat ik zei dat je gewoon een destructor moet implementeren. IDisposable is gewoon een (belangrijke) optimalisatie.
(in .Net heet dat eigenlijk de Finalizer)
In C# heet het een destructor, je mag in C# niet zelf de Finalize() implementeren. De compiler gooit er wat logic omheen en dat wordt uiteindelijk de finalizer. ;)
farlane schreef op vrijdag 24 augustus 2012 @ 09:50:
Begrijp ik het goed dat je in .NET geen fatsoenlijke manier hebt om resources die in een object worden beheerd gegarandeerd op te ruimen? IDisposable werkt alleen icm een using/manuele aanroep door de gebruiker van het object die dat kan 'vergeten', en de 'finalizer' wordt pas na 2 GC runs aangeroepen.
Nee, dat begrijp je niet goed. Gewoon een destructor/finalizer implementeren.

[ Voor 29% gewijzigd door .oisyn op 24-08-2012 10:29 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
.oisyn schreef op vrijdag 24 augustus 2012 @ 10:17:
[...]

Nee, je moet het in de destructor doen. Van Dispose is niet gegarandeerd dat ie wordt aangeroepen. Uiteraard kun je het beste óók IDisposable implementeren zodat je ze al eerder op kunt ruimen, maar als je het niet in de destructor doet en niemand roemt Dispose() aan dan leak je resources. Vandaar dat ik zei dat je gewoon een destructor moet implementeren. IDisposable is gewoon een (belangrijke) optimalisatie.
Dispose wordt inderdaad alleen aangeroepen na een using block (gegarandeerd volgens mij) maar je kunt hem natuurlijk ook altijd handmatig aanroepen daar doelde ik op.
In C# heet het een destructor, je mag in C# niet zelf de Finalize() implementeren. De compiler gooit er wat logic omheen en dat wordt uiteindelijk de finalizer. ;)
Hmm mijn bron zegt dit:
Instead of destructors, C# has finalizers which are implemented by overriding the Finalize method defined on the base Object class (though C# somewhat confusingly uses the C++ destructor syntax ~Object for this
Maar MSDN (de juiste bron natuurlijk) zegt inderdaad dat een destructor geen finalizer is maar wel de Finalize methode aanroept. Je hebt helemaal gelijk dus.

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

roy-t schreef op vrijdag 24 augustus 2012 @ 11:53:
[...]

Dispose wordt inderdaad alleen aangeroepen na een using block (gegarandeerd volgens mij) maar je kunt hem natuurlijk ook altijd handmatig aanroepen daar doelde ik op.
Ja, maar wat je leek te suggereren is dat je geen destructor/finalizer moet implementeren "want dat is toch te laat". Dat lijkt me een onjuiste conclusie. Die destructor is de garantie dat de resource hoe dan ook ooit vrijgegeven zal gaan worden. Het daarnaast implementeren van IDisposable is natuurlijk wel aan te raden.

[ Voor 7% gewijzigd door .oisyn op 24-08-2012 11:58 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
Even gefixed om de verwarring te voorkomen :)

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-09 22:43
.oisyn schreef op vrijdag 24 augustus 2012 @ 10:17:
Nee, dat begrijp je niet goed. Gewoon een destructor/finalizer implementeren.
Nja maar die wordt dus pas na 2 GC runs aangeroepen als ik het verhaal van roy-t lees. Ook niet echt ideaal.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
Nouja zo rampzalig is het niet dat is het mooie van de garbage collection:

Situatie 1: je maakt bijna geen garbage en daardoor duurt het erg lang voordat er 2 GC runs geweest zijn.
Situatie 2: je maakt snel veel garbage en daardoor zijn er snel 2 GC runs.

In beide gevallen wordt er garbage opgeruimd als het nodig is en blijft je onnodige geheugen gebruik laag. Dus je hoeft je nergens druk om te maken.

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

farlane schreef op vrijdag 24 augustus 2012 @ 19:05:
[...]

Nja maar die wordt dus pas na 2 GC runs aangeroepen als ik het verhaal van roy-t lees. Ook niet echt ideaal.
Maar dat was je vraag niet. De GC ruimt het gegarandeerd op als jij een dtor implementeert. Ideaal is het pas als de gebruiker van je object zelf expliciet aangeeft dat je object opgeruimd kan worden (hence IDisposable). Nog idealer is gewoon C++/CLI gebruiken, want dan heb je gewoon automatisch finalization als je object uit scope gaat, net als in C++ :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-09 22:43
roy-t schreef op vrijdag 24 augustus 2012 @ 19:09:
In beide gevallen wordt er garbage opgeruimd als het nodig is en blijft je onnodige geheugen gebruik laag. Dus je hoeft je nergens druk om te maken.
Integendeel, je moet je nu nog drukker maken om het opruimen want je moet nu gaan bedenken of je IDisposable moet implementeren ( die moet controleren of er al gedisposed is en of er gedisposed wordt blijkbaar ) of ook nog een destructor daarbij.
Nouja zo rampzalig is het niet dat is het mooie van de garbage collection:

Situatie 1: je maakt bijna geen garbage en daardoor duurt het erg lang voordat er 2 GC runs geweest zijn.
Situatie 2: je maakt snel veel garbage en daardoor zijn er snel 2 GC runs.
Als je native resources (handles bv) gebruikt is die er voor de gc niet echt veel 'garbage'. Je verhaal gaat volgens mij alleen op voor geheugen/objecten binnen de gc.
Nog idealer is gewoon C++/CLI gebruiken, want dan heb je gewoon automatisch finalization als je object uit scope gaat, net als in C++
Ik vind dat eigenlijk een stuk eenduidiger.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:56
Als je een class maakt, die zelf disposable instances instantieert, dan moet je gewoon doen wat .oisyn al zegt:
Het disposable pattern gaan implementeren.

Ik heb zelf een base-class 'Disposable' gemaakt, die dat pattern al implementeert en waarbij ik gewoon nog een method moet overriden. Indien mogelijk erf ik dan gewoon van die class over ipv nogmaals de IDisposable interface te implementeren.

Echter, het wel of niet moeten hebben van een finalize method vind ik toch nog zo simpel / straightforward niet; lees het stukje over finalization internals

Je zou dus enkel maar een finalizer moeten schrijven, als je daadwerkelijk unmanaged resources in je class beheert. Anders is het beter om geen finalizer te schrijven.

[ Voor 33% gewijzigd door whoami op 24-08-2012 20:51 ]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-09 22:43
whoami schreef op vrijdag 24 augustus 2012 @ 20:00:
Als je een class maakt, die zelf disposable instances instantieert, dan moet je gewoon doen wat .oisyn al zegt:
Ik heb zelf een base-class 'Disposable' gemaakt, die dat pattern al implementeert en waarbij ik gewoon nog een method moet overriden. Indien mogelijk erf ik dan gewoon van die class over ipv nogmaals de IDisposable interface te implementeren.
Je hebt een class gemaakt die een interface implementeert waarvan je moet afleiden om Dispose/Finalize goed te doen?
Kan aan mij liggen maar dat is voor mij geen indicatie dat het er eenvoudiger op is geworden ..

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 16-09 15:42

Sebazzz

3dp

Voor Disposable gebruik ik een Resharper live template. Gedumpt op Gist voor de geïnteresseerden.

https://gist.github.com/3453874

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
Waarom wordt er bij dit pattern in de destructor Dispose aangeroepen met het argument false?

Je hebt nu
C#:
1
2
if (!disposed) {
        if (disposing) {


Wat ga je doen op het moment dat het object nog niet gedisposed is en je ook niet aan het disposen bent, zoals blijkbaar bij dit pattern vanuit de destructor? Ik bedoel finalizen door de GC wordt gesupressed in dit geval dus blijf je dan niet met garbage?

Waar zo'n kleine vraag toch niet goed voor is, zo leren we allemaal weer wat, yay voor forums! :)

[ Voor 9% gewijzigd door roy-t op 24-08-2012 20:45 ]

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

In die if zet je alleen het disponsen van managed objects (IDisposables). Vanuit de finalizer doe je Dispose(false) omdat het nergens op slaat om in je finalization nog objecten te gaan zitten disposen - als jij de enige referentie hebt zullen zij ook wel gefinalized worden en dus hun unmanaged resources disposen indien nodig. Wordt er echter Dispose() aangeroepen, dan wil je je managed resources wél expliciet disposen.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
Check check dubbel check :)

~ Mijn prog blog!

Pagina: 1