Wie ruft der GC den Finalizer auf?



  • Tut mir leid, wenn diese Frage schon gestellt wurde, aber da ich erst seit kurzem lerne versteh ich die Arbeit des Finalizers noch nicht richtig: So wie ich es gelesen habe, wird der doch theoretisch vom GC aufgerufen, da hab ich mir einen test gestattet:

    ref class TestKlasse
    {
    	int *intZg;
    	char unbenutzt;
    public:
    	TestKlasse() : intZg(new int[100000]) {}
    	!TestKlasse() {delete[] intZg;}
    	~TestKlasse() {this->!TestKlasse();}
    };
    
    void TuWas()
    {
    	TestKlasse ^k=gcnew TestKlasse;
    }
    
    int main()
    {
    	for(int i=0;i<1000;i++)
    		TuWas();
    	std::cout << "Ende" << std::endl;
    	getchar();
    	return 0; // Ende
    }
    

    Nur bei erscheinen von "Ende" auf dem bildschirm habe ich 400 MB belegt, was hab ich falsch gemacht?



  • Der GC tut das wenn ers für richtig hält.
    IDisposable.Dispose (und das ist das was ~TestKlasse() letzendlich ist) wird durch delete aufgerufen:

    void TuWas()
    {
        TestKlasse ^k=gcnew TestKlasse;
        delete k;
    }
    


  • Wie theta schon gesagt hat, solltest du dich nicht auf Finalizer sondern auf IDisposable::Dispose, sprich den Destruktor konzentrieren. Ebenfalls gültig ist hier die standardmässige C++-Semantik:

    void TuWas()
    {
        TestKlasse k;
        // Beim Verlassen des Scopes wird TestKlasse::~TestKlasse() aufgerufen und das Objekt zerstört.
    }
    


  • theta schrieb:

    Der GC tut das wenn ers für richtig hält.

    Der GC tut das genau genommen gar nicht, der Finalizer-Thread tut das.
    Wann und wie steht in der MSDN. Alles gut dokumentiert.

    FinalizerFeind schrieb:

    Nur bei erscheinen von "Ende" auf dem bildschirm habe ich 400 MB belegt, was hab ich falsch gemacht?

    Na, du hast ne "deterministisch finalisierbare" Klasse gebastelt (eine mit "Destruktor" aka. IDisposable::Dispose), und finalisierst die Instanzen die du davon anlegst dann nicht.

    Richtig ginge es so:

    void TuWas()
    {
        TestKlasse ^k=gcnew TestKlasse;
    
        // ...
    
        delete k;
    }
    

    bzw. gleichbedeutend und IMO viel eleganter so:

    void TuWas()
    {
        TestKlasse k;
    
        // ...
    
    } // implizites "delete k"
    

    Und natürlich

    FinalizerFeind schrieb:

    was hab ich falsch gemacht?

    Ein Werkzeug verwendet welches du nicht verstehst.



  • Man sollte auch beachten, dass im Finalizer *keine* Managed Objekte verwendet werden dürfen!!! Sowas kann ganz böse Enden... im besten Fall führt es zu "Object resurection".... im schlimmsten Fall zu erheblichen Verzögerungen...

    Im Finalizer darf man nur auf *unmanged* Dinge zugreifen!


Anmelden zum Antworten