2011-08-22 14 views
5

Moja aplikacja jest połączeniem kodu C# i C++. Moduł startowy napisany w C# ładuje podczas fazy inicjalizacji moduł C++ poprzez mechanizm COM (Component Object Model). Wszystko działało poprawnie, dopóki nie zdecydowałem się dodać do C# części usługi wcf. Wszystkie wywołania serwisowe wcf są kierowane do kodu C++ za pomocą COM. Po dodaniu nowych metod zauważyłem wycieki pamięci w oknie wyjściowym. Więc dodałem breakpoint do desktruktora klasy C++, jak widać na zrzucie ekranu. Od tego momentu dziwne rzeczy zaczęły się dziać. Po osiągnięciu punktu przerwania programu niespodziewanie ulega awarii. Pierwszą dziwną rzeczą jest to, że kiedy uruchamiam program bez ustawiania punktu przerwania, kończy się on łaskawie. Drugą dziwną rzeczą jest to, że sposób, w jaki program się zawiesza, działa tak, jakby działał bez debuggera. Po kliknięciu przycisku "Otwórz w debugerze" (lub coś podobnego) pojawia się komunikat o błędzie: "Program jest już otwarty w debugerze." Brak komunikatu w oknie wyjściowym, który mógłby wskazać mi źródło błędu, żaden podejrzany kod. Dodanie okna komunikatu do początku destruktora powoduje wyświetlenie części ułamka sekundy, a następnie zamknięcie całej aplikacji (bez dodawania możliwości użytkownika do przeczytania tego, co jest wyświetlane w oknie komunikatu). Rozpaczliwie szukając jakiejkolwiek wskazówki.Dziwne awarie podczas debugowania obiektu COM destructor

P.S. Problemy występują tylko wtedy, gdy metoda wcf została wywołana co najmniej raz. Nie zależy, czy przepływ programu w tym konkretnym wywołaniu został przekierowany na poziom C++, czy też nie.

enter image description here

enter image description here

+0

Spróbuj użyć WinDbg zamiast debugera VS, aby uzyskać więcej informacji na temat awarii – SpaceghostAli

Odpowiedz

0

rozwiązane przez następujący kod:

public void Dispose() 
{ 
    Marshal.Release(internal_interface_ptr); 
    internal_interface_ptr = IntPtr.Zero; 
    Marshal.ReleaseComObject(internal_interface); 
    Marshal.ReleaseComObject(internal_interface); 
    internal_interface = null; 
} 

Poza tym jeszcze jedna wzmianka wisiał w kodu C++. Podsumowując, głównym błędem z mojej strony było zapomnienie o wyraźnym zwolnieniu obiektu COM w kodzie C#. Nawet jeśli garbage collector zajmuje się zarządzaniem pamięcią, nie dotyczy to modułów napisanych w innych językach programowania. Obiekt COM destructor został wywołany bardzo niedawno, gdy konkretna biblioteka połączona dynamicznie miała zostać wyładowana z pamięci, co spowodowało problemy. Mam nadzieję, że wyjaśniłem to wystarczająco wyraźnie.

1

Dzwoniąc C# od C++ czasami garbage collector nie prawidłowo sprawdzony przed końcem programu. Spróbuj wymusić usuwanie śmieci na końcu twojego kodu C#.

+0

Zawieszenie się, jakby cud zniknął, niemniej jednak program kończy się, zanim wszystkie destruktory COM zakończyły swoją pracę. Zobacz mój drugi zrzut ekranu. W tym konkretnym momencie program jest tuż przed jego zakończeniem, ale niektóre destruktory COM nie zostały jeszcze wywołane. Po ich wezwaniu ich praca kończy się nagle. – truthseeker

+0

Rozwiązano według następującego kodu: publiczny pustka Usuń() { Marshal.Release (internal_interface_ptr); internal_interface_ptr = IntPtr.Zero; Marshal.ReleaseComObject (internal_interface); internal_interface = null; } – truthseeker

+0

Nie jestem do końca pewien, co masz na myśli mówiąc: "Rozbicie, jakby cud zniknął". Myślę, że zanim wyślesz zbieracz garbase, będziesz musiał wymusić na swoich usługach likwidację. Sprawdź, czy usługa ServicesToRun lub usługi są usuwane przed uruchomieniem kolekcjonera garbase, w przeciwnym razie działa dobrze. – mydogisbox