2010-03-20 19 views
5

Moja czysta biblioteka DotNET działa jako wtyczka wewnątrz niezarządzanej aplikacji komputerowej. Dostaję stały (choć niski) strumień raportów o awariach, które wydają się wskazywać na problem z uchwytami GDI (czcionki w komunikatach o błędach itp. Powracają do czcionek systemowych, wyświetlanie wszystkich rodzajów kontrolek się załamuje, masowe awarie wkrótce po).Uchwyty GDI w aplikacji DotNET

Moje formularze mają niewiele elementów sterujących, ale wykonuję wiele rysunków GDI + w elementach sterujących użytkownika. Jaki jest dobry sposób, aby powiedzieć, ile uchwytów używam, a nawet wyciek?

Dzięki David

+1

Przede wszystkim warto zaktualizować pytanie typowym przykładem wyglądu kodu rysunkowego. W ten sposób możesz uzyskać konkretne odpowiedzi na temat rzeczy, które być może powinieneś poprawić. –

Odpowiedz

2

Musiałem poradzić sobie z tym samym problemem w przeszłości. Aby sprawdzić, ile obiektów GDI jest przydzielanych przez aplikację, można użyć bezpłatnego narzędzia o nazwie GDIUsage.

W moim przypadku aplikacja uległa awarii, ponieważ przydzielała więcej niż 10.000 obiektów GDI, co jest sztywnym ograniczeniem w systemie Windows XP. Warto się nad tym zastanowić.

mam blogu o tym problemie tutaj:
http://megakemp.com/2009/02/25/gdi-memory-leak-in-windows-forms/

+0

Dzięki! To pozwoli mi zacząć. –

1

Łatwo jest zobaczyć z Taskmgr.exe, kartę Procesy. Wyświetl + wybierz kolumny, zaznacz obiekty GDI.

Twój opis rzeczywiście pasuje do wycieku uchwytu. To nie powinno się zdarzyć w zarządzanym programie, finalizator powinien zadbać o to, abyś zapomniał wywołać Dispose(). Chyba, że ​​nie zużyjesz dużo miejsca na śmieci. Mogą to być również niezarządzane aplikacje, które przeciekają, bardzo często.

+2

Jeśli zarządzany kod pozostawia GC w celu wywołania metody "Dispose", może to również prowadzić do problemów, ponieważ GC działa w wątku równoległym i działa w dogodny dla siebie sposób. Dlatego przy korzystaniu z obiektów GDI w zarządzanym kodzie dobrze jest zawijać je między blokami 'using'. –

+0

Dzięki Nobugz. "To nie powinno się zdarzyć w zarządzanym programie". Wiem i jestem prawie pewien, że nie nazywam Dispose on * every * Pen and Brush oraz GraphicsPath, które tworzę. Ponieważ zgłoszone problemy nie występują, gdy moja wtyczka nie jest załadowana, zakładam, że to moja wina, a nie niezarządzana aplikacja. –

3

Oprócz monitora wydajności można wypróbować starą dobrą funkcję Task Manager.

Sprawdź kartę Process i kliknij View> i sprawdź obiekty GDI.

+0

Dzięki Paolo, niestety moja aplikacja działa jako wtyczka w większej aplikacji, i chce być w stanie zobaczyć, które uchwyty są używane tylko dla mojego kodu. Nie jestem do końca pewien, czy nie jest to możliwe, ale byłoby to lepsze niż ogólny przegląd. –

1

Jeśli jeszcze tego nie zrobiłeś, upewnij się, że wywołujesz IDisposable.Dispose na dowolnym obiekcie rysunkowym GDI +, którego używasz. byś zwykle zrobić to z C# using konstruktu, np .:

using(Brush brush = ...) 
{ 
    ... 
} 

Narzędzia do analizy statycznej kodu takie jak FxCop lub wersji wbudowanej w wersji Team System Visual Studio może pomóc wykryć przypadki, w których nie uda się wywołać Dispose.

Niewykonanie połączenia Usunięcie w ten sposób może spowodować wyciek rączki, ponieważ uchwyt nie zostanie odzyskany, dopóki pojemnik na śmieci nie będzie pasował.

3

spojrzeć na GDIView (jest to freeware):

GDIView jest unikalnym narzędziem, które wyświetla listę uchwytów GDI (pędzle, długopisy, czcionki, mapy bitowe i inne) otwierane przy każdym procesie. Wyświetla on całkowitą liczbę dla każdego rodzaju uchwytu GDI , a także szczegółowe informacje o każdym uchwycie: . To narzędzie o numerze może być przydatne dla programistów, którzy potrzebują wykrycia wycieku zasobów GDI w ich oprogramowaniu.

alt text http://www.nirsoft.net/utils/gdiview.gif

Uwaga, że auto-odświeżania jest domyślnie wyłączona, ale można ją włączać i skonfigurowane dla poszczególnych przedziałów: Options -> Auto Refresh -> Every [N] seconds

1

GDIObj, darmowe narzędzie dostarczane przez Feng Yuan jako Przykładowy program do jego książki, Windows Graphics Programming: Win32 GDI and DirectDraw może być przydatny.

przeciwieństwie do Menedżera zadań, dostarcza liczniki dalszy podział różnych typów uchwytów GDI tym DC, Region, Bitmap, paleta, czcionka, szczotki, itp

(jednak tylko dostarcza informacji liczyć podczas GDIView zapewnia . więcej szczegółów na temat uchwytów)

2

Począwszy GDIView z odpowiedzią Ray Vega, znalazłem this tip:

[DllImport("User32")] 
extern public static int GetGuiResources(IntPtr hProcess, int uiFlags); 

    public static void GetGuiResourcesGDICount()  
    { 
     //Return the count of GDI objects.   
     Console.WriteLine("GDICount"+GetGuiResources(System.Diagnostics.Process.GetCurrentProcess().Handle, 0));  
    } 

    private void button1_Click(object sender, System.EventArgs e) 
    { 
     GetGuiResourcesGDICount(); 
    } 

GDIView poinformował, że był obiekty czcionki TH w którym wyciekły; Następnie dodałem wywołania GetGuiResources do naszego kodu logowania, aby wykryć, w którym momencie zostało wywołane tworzenie obiektu.

W naszym przypadku tekst kontrolki Label został zaktualizowany, gdy jego rodzic UserControl został ukryty w oknie tła. Spowodowałoby to wyciek czcionek GDI. Aby to naprawić, zmieniliśmy naszą logikę, aby nie aktualizować Label, chyba że był on aktualnie widoczny na ekranie. Aby ustalić, czy jest on widoczny, przechowujemy zapis ostatniego ostatniego malowania UserControl.