Autor Beitrag
Sascha L
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 25



BeitragVerfasst: Di 23.02.10 21:03 
Hallo,

ich habe ein riesiges Speicherleck, welches ich einfach nicht finde. Ich hoffe, dass mir hier jemand weiterhelfen kann. Wenn ich folgenden Code z.B. 1000mal ausführe, habe ich ein Speicherleck von 300 KB!


ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
Graphics gbuffer = CreateGraphics();
            IntPtr screenDC = gbuffer.GetHdc();
            IntPtr memDC = CreateCompatibleDC(screenDC);
            IntPtr bufferDC = CreateCompatibleBitmap(screenDC, Width, Height);

            Graphics g = Graphics.FromHdc(memDC);
            g.Clip = new Region(new Rectangle(00, Width, Height));

            IntPtr old = SelectObject(memDC, bufferDC);

            g.Clear(Color.FromArgb((int)color));
            g.Dispose();

            BitBlt(screenDC, 00, Width, Height, memDC, 000x00CC0020);
            
            SelectObject(memDC, old);
           
            DeleteObject(bufferDC);          
            DeleteDC(memDC);
            gbuffer.ReleaseHdc(screenDC);
            gbuffer.Dispose();


Gruß
Sascha
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Di 23.02.10 22:33 
Bist Du sicher, dass es ein Speicherleck ist oder kann es sein, dass der GC einfach noch nicht aufgeräumt hat?

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Sascha L Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 25



BeitragVerfasst: Di 23.02.10 22:51 
Hi,

ja, da bin ich mir aus folgenden zwei Gründen sicher:

a) Es sind fast nur native Funktionen, auf die der GC keinen Einfluss hat. Und selbst wenn ich GC.Collect() und WaitForPendingFinalizers() aufrufe, ändert sich am Speicherleck nichts

b) Wenn ich den Code mehr als 1000mal aufrufe, z.B. 100.000mal ist GDI systemweit im Eimer. D.h. selbst wenn ich meine Anwendung beende, können andere Anwendungen nicht mehr korrekt zeichnen, weil wohl ja nur eine bestimmte Anzahl an GDI Objekten systemweit möglich sind und die anscheinend von mir nicht richtig frei gegeben werden.


EDIT: Hab total vergessen zu erwähnen, dass ich das Problem auf Windows Mobile mit dem .NET CF habe! Ob es auf dem PC auch der Fall ist, weiß ich nicht.
Sascha L Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 25



BeitragVerfasst: Mi 24.02.10 16:49 
Hab das Problem.

"g" ist das Problem. Trotz g.Dispose() und g = null bleibt es im Speicher. Erst ein Collect() und WaitForPendingFinalizers() löscht es. Die GC-Funktionen kann ich aber nicht bei jedem Zeichnen aufrufen, da das Zeichnen sonst extrem lahm wird. Gibt es sonst noch eine Möglichkeit "g" komplett zu löschen?
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mi 24.02.10 21:02 
Ich kann es zwar nicht testen, und du hast ja eigentlich recht eindeutige Ergebnisse, trotzdem muss ich einwerfen: Das kann einfach nicht sein ;) .
Graphics.Dispose gibt das Handle frei und unterdrückt den Finalizer, GDI und GC können also eigentlich nicht zusammenhängen. Und die ~16 Bytes pro Graphics-Instanz dürften es auch nicht raushauen :) .

_________________
>λ=
Sascha L Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 25



BeitragVerfasst: Do 25.02.10 00:10 
Also ich kann nur so viel sagen, dass es bei mir eindeutig das Graphics-Objekt ist. Ich habe es noch so weit optimiert, dass ich gbuffer nicht mehr benötigte (nutze nun GetDC), aber g brauch ich (der obige Code ist nämlich nur ein Beispiel). Wenn ich g nicht verwende, gibt es kein Speicherleck. Nutze ich g, gibt es ein Speicherleck. Rufe ich den GC nach g.Dispose() und g = null auf, ist das Speicherleck ebenfalls weg. Das Problem ist nur, dass in diesem Falle die Performance natürlich stark leidet, wenn ich jedes Mal den GC aufrufen muss.

Rufe ich den GC nicht auf, wird der Speicher zu keiner Zeit wieder freigegeben. Was wie gesagt bei Windows Mobile fatal ist, weil mal schnell 10-20 MB zusammen kommen und das ist für die meisten WM-Geräte schon zu viel, sodass entweder nichts mehr reagiert oder andere Anwendungen nichts mehr zeichnen können, da alle GDI-Objekte vergeben sind (gibt nur eine maximale Anzahl erlaubter GDI-Objekte).