Czy można zadzwonić do RCW z finalizera?

Mam zarządzany obiekt, który wywołuje serwer COM, aby przydzielić trochę pamięci. Zarządzany obiekt musi ponownie wywołać serwer COM, aby zwolnić tę pamięć przed odejściem zarządzanego obiektu, aby uniknąć wycieku pamięci. Obiekt ten implementuje IDisposable, aby zapewnić prawidłowe wywołanie com zwalniające pamięć.

W przypadku, gdy metoda Dispose jest wywołana , a nie, chciałbym, aby finalizer obiektu zwolnił pamięć. Problem w tym, że zasady finalizacji są takie, że musisz nie uzyskuj dostępu do żadnych referencji, ponieważ nie wiesz, jakie inne obiekty zostały już wcześniej GC ' D i / lub sfinalizowane. W ten sposób jedynym dotykalnym stanem obiektu są pola (najczęściej spotykane są uchwyty).

Ale wywołanie serwera COM wymaga przejścia przez Runtime callable wrapper (RCW) w celu uwolnienia pamięci, którą mam plik cookie do przechowywania w polu. czy RCW jest bezpieczne do wywołania z finalizatora (czy jest gwarantowane, że nie został GC ' D lub sfinalizowany w tym punkt)?

Dla tych z Was, którzy nie są zaznajomieni z finalizacją, chociaż wątek finalizatora działa w tle zarządzanej appdomeny podczas jej działania, at dla tych przypadków dotykanie referencji teoretycznie byłoby w porządku, finalizacja odbywa się również przy zamykaniu appdomeny i W dowolnej kolejności - nie tylko w kolejności relacji odniesienia. Ogranicza to to, co można założyć, że można bezpiecznie dotknąć z finalizera. Wszelkie odniesienia do zarządzanego obiektu mogą być " złe " (gromadzona pamięć) nawet jeśli odniesienie nie jest null.

Update : właśnie próbowałem i dostałem to:

Nieobsługiwany wyjątek typu ' System.Runtime.InteropServices.InvalidComObjectException ' wystąpił w myassembly.dll

Dodatkowe informacje: obiekt COM, który został oddzielony od podstawowego RCW, nie może być użyty.

Author: Andrew Arnott, 2009-10-15

2 answers

Dowiedziałem się od samego zespołu CLR, że rzeczywiście nie jest to bezpieczne -- chyba że przydzielasz GCHandle na RCW, dopóki jest to nadal bezpieczne (kiedy po raz pierwszy zdobędziesz RCW). Zapewnia to, że GC i finalizer nie zsumowały RCW przed zakończeniem zarządzanego obiektu, który musi go wywołać.

class MyManagedObject : IDisposable
{
    private ISomeObject comServer;
    private GCHandle rcwHandle;
    private IServiceProvider serviceProvider;
    private uint cookie;

    public MyManagedObject(IServiceProvider serviceProvider)
    {
        this.serviceProvider = serviceProvider;
        this.comServer = this. serviceProvider.GetService(/*some service*/) as ISomeObject;
        this.rcwHandle = GCHandle.Alloc(this.comServer, GCHandleType.Normal);
        this.cookie = comServer.GetCookie();
    }

    ~MyManagedObject()
    {
        this.Dispose(false);
    }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // dispose owned managed objects here.
        }

        if (this.rcwHandle.IsAllocated)
        {
            // calling this RCW is safe because we have a GC handle to it.
            this.comServer.ReleaseCookie(this.cookie);

            // Now release the GC handle on the RCW so it can be freed as well
            this.rcwHandle.Free();
        }
    }
}

Okazuje się, że w moim konkretnym przypadku, moja aplikacja jest hosting CLR sam. Dlatego dzwoni do mscoree!CoEEShutdownCOM przed wątkiem finalizer dostaje się do uruchomienia, co zabija RCW i powoduje błąd InvalidComObjectException, który widziałem.

Ale w normalnych przypadkach, gdy CLR sam się nie hostuje, powiedziano mi, że to powinno zadziałać.

 16
Author: Andrew Arnott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-18 15:02:23

Nie dostęp do RCW z wątku finalizera nie jest bezpieczny. Po dotarciu do wątku finalizera nie masz gwarancji, że RCW nadal żyje. Możliwe jest, że będzie on wyprzedził Twój obiekt w kolejce finalizera, a tym samym zostanie zwolniony do czasu uruchomienia destruktora w wątku finalizera.

 7
Author: JaredPar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-15 17:54:02