Eigene ControlLibrary - Memoryleak

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 76 Antworten in diesem Thema. Der letzte Beitrag () ist von Daniel Baumert.

    Daniel Baumert schrieb:

    Projektmappe
    wäre gut.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    MangoETheme ist die Library mit den Controls.

    MangoEP die WinForm, auf der die Controls benutzt werden.


    Um die WinForm zu öffnen:


    Bei MangoEp musst Du in den Ordner "MangoE" und die
    Datei "Mangoop.vbproj" öffnen, denn die .Sln ist irgendwie abhanden gekommen :)

    Brauchst dann nur mal auf die Tabpage D klicken und dann mal
    innerhalb der Tabpage irgendwo mit der Maus klicken.

    Dann siehste schon den Fehler.
    Dateien
    • All.zip

      (1,37 MB, 92 mal heruntergeladen, zuletzt: )
    Hier zwei kleine Bildchen, die deinen Arbeitsspeicherbedarf zeigen:

    Da siehst du, was genau das Problem an deiner Anwendung ist: Dreißigtausend DeviceContexts.

    Was genau dein Problem ist: Du erstellst ein Bitmap, dazu ein GraphicsContext, da schreibst alles rein und machst am Ende ein B.Clone() WARUM!? Damit erstellst du eine NEUE Instanz, die am Ende NIEMALS bereinigt wird. Ja es bringt Probleme, aber denen kannst du entgegen wirken, indem du bspw. dein Bitmap lokal in der Klasse speicherst.
    Guck dir doch mal diese Grafik an:

    Du hast teilweise 22996 Zuweisungen (NEUE Objekte). Und das der Arbeitsspeicher fällt, liegt NUR daran, dass die GarbageCollection in .NET ordentlich funktioniert. In nativem C++ hättest du schon längst eine OutOfMemory-Exception. Überlege GENAU was dein Code, bzw. das Programm macht, wenn es bestimmten Befehlen folgt und ändere entsprechend deinen Code.
    Vom Stil mal ganz zu schweigen - der ist grausam. Alles in eine Datei und dann auch noch vollkommen unstrukturiert. Aber gut, das ist jedem selbst überlassen.
    @Daniel Baumert ich hab mal Dein Projekt beräumt.
    Kompiliere es, Du bekommst beliebig viele Warnungen für falsch implementierte Dispose()-Prozeduren.
    Behebe die Fehler und es sollte freundlicher laufen.
    Dateien
    • All.zip

      (697,74 kB, 88 mal heruntergeladen, zuletzt: )
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Daniel Baumert schrieb:

    verändert
    Projektmappe mit beiden Projekten drin.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Daniel Baumert schrieb:

    hochgeladen
    Ich habe eine Menge Warnungen / Fehler gefunden, die ich Dich bitte zu beheben.
    Kompiliere mein Projekt.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Okay, aber einige Fehler sind mir unklar. Beispielsweise:

    C#-Quellcode

    1. private MouseState Statee;


    Warnung 8 Dem Feld 'MangoERadioButton.State' wurde ein Wert zugewiesen, der aber nie verwendet wird.

    Obwohl ich Folgendes habe:

    C#-Quellcode

    1. protected override void OnMouseEnter(System.EventArgs e)
    2. {
    3. base.OnMouseEnter(e);
    4. Statee = MouseState.Over;
    5. this.Invalidate();
    6. }


    Habe schon auf Bereinigen und neu Erstellen geklickt, aber der Fehler bleibt..

    Darüber hinaus frage ich mich, wie AliveDevil das mit den Instanzen meint.

    -Wie soll ich das Ohne

    C#-Quellcode

    1. .Clone()
    machen?
    -Welche Bitmaps soll ich bitte klassenglobal machen um neue Instanzen zu vermeiden?

    Daniel Baumert schrieb:

    Und nun?
    Diese Warnungen:
    1>------ Build started: Project: MangoETheme, Configuration: Debug Any CPU ------
    1>C:\Temp\Test\All\MangoETheme\MangoETheme.cs(253,10,253,17): warning CS0108: 'MangoEControlBox.Dispose()' hides inherited member 'System.ComponentModel.Component.Dispose()'. Use the new keyword if hiding was intended.
    1>C:\Temp\Test\All\MangoETheme\MangoETheme.cs(346,10,346,17): warning CS0108: 'MangoEForm.Dispose()' hides inherited member 'System.ComponentModel.Component.Dispose()'. Use the new keyword if hiding was intended.
    1>C:\Temp\Test\All\MangoETheme\MangoETheme.cs(420,10,420,17): warning CS0108: 'MangoEGroupBox.Dispose()' hides inherited member 'System.ComponentModel.Component.Dispose()'. Use the new keyword if hiding was intended.
    1>C:\Temp\Test\All\MangoETheme\MangoETheme.cs(510,10,510,17): warning CS0108: 'MangoEButtonOrange.Dispose()' hides inherited member 'System.ComponentModel.Component.Dispose()'. Use the new keyword if hiding was intended.
    1>C:\Temp\Test\All\MangoETheme\MangoETheme.cs(602,10,602,17): warning CS0108: 'MangoEButtonGray.Dispose()' hides inherited member 'System.ComponentModel.Component.Dispose()'. Use the new keyword if hiding was intended.
    1>C:\Temp\Test\All\MangoETheme\MangoETheme.cs(722,10,722,17): warning CS0108: 'MangoECheckBox.Dispose()' hides inherited member 'System.ComponentModel.Component.Dispose()'. Use the new keyword if hiding was intended.
    1>C:\Temp\Test\All\MangoETheme\MangoETheme.cs(848,10,848,17): warning CS0108: 'MangoERadioButton.Dispose()' hides inherited member 'System.ComponentModel.Component.Dispose()'. Use the new keyword if hiding was intended.
    1>C:\Temp\Test\All\MangoETheme\MangoETheme.cs(998,10,998,17): warning CS0108: 'MangoETextBox.Dispose()' hides inherited member 'System.ComponentModel.Component.Dispose()'. Use the new keyword if hiding was intended.
    1>C:\Temp\Test\All\MangoETheme\MangoETheme.cs(1069,10,1069,17): warning CS0108: 'StudioMinimizeButton.Dispose()' hides inherited member 'System.ComponentModel.Component.Dispose()'. Use the new keyword if hiding was intended.
    1>C:\Temp\Test\All\MangoETheme\MangoETheme.cs(1140,10,1140,17): warning CS0108: 'StudioExitButton.Dispose()' hides inherited member 'System.ComponentModel.Component.Dispose()'. Use the new keyword if hiding was intended.
    1>C:\Temp\Test\All\MangoETheme\MangoETheme.cs(1239,10,1239,17): warning CS0108: 'AppleCheckBox.Dispose()' hides inherited member 'System.ComponentModel.Component.Dispose()'. Use the new keyword if hiding was intended.
    1>C:\Temp\Test\All\MangoETheme\MangoETheme.cs(1326,10,1326,17): warning CS0108: 'AppleRadioButton.Dispose()' hides inherited member 'System.ComponentModel.Component.Dispose()'. Use the new keyword if hiding was intended.
    1>C:\Temp\Test\All\MangoETheme\MangoETheme.cs(1441,10,1441,17): warning CS0108: 'FakeMacButton.Dispose()' hides inherited member 'System.ComponentModel.Component.Dispose()'. Use the new keyword if hiding was intended.
    1>C:\Temp\Test\All\MangoETheme\MangoETheme.cs(1635,14,1635,21): warning CS0108: 'MangoETrackBar.Dispose()' hides inherited member 'System.ComponentModel.Component.Dispose()'. Use the new keyword if hiding was intended.
    1>C:\Temp\Test\All\MangoETheme\MangoETheme.cs(613,24,613,29): warning CS0414: The field 'MangoECheckBox.State' is assigned but its value is never used
    1>C:\Temp\Test\All\MangoETheme\MangoETheme.cs(732,24,732,29): warning CS0414: The field 'MangoERadioButton.State' is assigned but its value is never used
    1> MangoETheme -> C:\Temp\Test\All\MangoETheme\bin\Debug\MangoETheme.dll
    2>------ Build started: Project: Mangoop, Configuration: Debug Any CPU ------
    2> Mangoop -> C:\Temp\Test\All\MangoEp\bin\Debug\Mangoeeee.exe
    ========== Build: 2 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Daniel Baumert schrieb:

    muss es funktionieren eigentlich.
    Ja, er kompiliert.
    Läuft er nun ruhiger?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ne, absolut nicht... Hat sich rein gar nichts verändert.


    Wie schreibe ich das jetzt um,ohne soviele Device Context machen zu müssen?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Daniel Baumert“ ()

    Daniel Baumert schrieb:

    Wie schreibe ich das jetzt um
    Wie weit muss ich in Deinem Projekt stehen, um diese Frage beantworten zu können?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Du hast doch den Code , was soll ich dazu noch großartig sagen?

    Ich meine mir würde es ja reichen, wenn mir jemand nur ein Control so umschreiben würde, dass
    ich sehe, wie der/die jenige vorgeht beim Zeichnen.

    Weil laut AliveDevil scheint der Code nicht gut zu sein und man
    sollte s wohl grundlegend anders machen.

    Wie muss ich beispielsweise diese Klasse hier umschreiben?

    Spoiler anzeigen

    C#-Quellcode

    1. [DefaultEvent("Click")]public class MangoEGroupBox : ContainerControl
    2. {
    3. private int h_Height = 10;
    4. [Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    5. public int HeaderHeight
    6. {
    7. get { return h_Height; }
    8. set
    9. {
    10. if (h_Height == value || h_Height < 1 || h_Height < 5) return;
    11. h_Height = value;
    12. this.Invalidate();
    13. }
    14. }
    15. public MangoEGroupBox()
    16. {
    17. this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor | ControlStyles.FixedHeight, true);
    18. this.UpdateStyles();
    19. this.Size = new Size(200, 100);
    20. this.BackColor = Color.Transparent;
    21. }
    22. protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
    23. {
    24. using (Bitmap B = new Bitmap(Width, Height))
    25. {
    26. using (Graphics G = Graphics.FromImage(B))
    27. {
    28. Rectangle TopBar = new Rectangle(0, 0, Width - 1, HeaderHeight);
    29. Rectangle box = new Rectangle(0, 0, Width - 1, Height - 10);
    30. base.OnPaint(e);
    31. G.SmoothingMode = SmoothingMode.HighQuality;
    32. using(LinearGradientBrush bodygrade = new LinearGradientBrush(ClientRectangle, Color.White, Color.White, 120)){G.FillPath(bodygrade, Draw.RoundRectF(new Rectangle(0, 12, Width - 1, Height - 15), 1));}
    33. using(LinearGradientBrush outerBorder = new LinearGradientBrush(ClientRectangle, Color.FromArgb(50, 50, 50), Color.DimGray, 90)){G.DrawPath(new Pen(outerBorder), Draw.RoundRectF(new Rectangle(0, 12, Width - 1, Height - 15), 1));}
    34. using(LinearGradientBrush lbb = new LinearGradientBrush(TopBar, Color.FromArgb(87, 86, 81), Color.FromArgb(60, 59, 55), 90)){G.FillPath(lbb, Draw.RoundRectF(TopBar, 1));}
    35. using(SolidBrush sb = new SolidBrush(Color.FromArgb(50,50,50)))
    36. {
    37. using(Pen pe = new Pen(sb)){G.DrawPath(pe, Draw.RoundRectF(TopBar, 2));}
    38. }
    39. Font drawFont = new Font("Tahoma", (HeaderHeight / 2) + 3, FontStyle.Regular);
    40. G.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
    41. using(SolidBrush sb = new SolidBrush(Color.White)) {G.DrawString(Text, drawFont, sb, TopBar, new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });}
    42. e.Graphics.DrawImage((Image)B.Clone(), 0, 0);
    43. }
    44. }
    45. }
    46. new public void Dispose()
    47. {
    48. Dispose(true);
    49. // Suppress finalization.
    50. GC.SuppressFinalize(this);
    51. }
    52. }

    Daniel Baumert schrieb:

    Ich meine mir würde es ja reichen, wenn mir jemand nur ein Control so umschreiben würde

    RodFromGermany schrieb:

    Wie weit muss ich in Deinem Projekt stehen
    Sorry, wir stehen nicht auf dem Marktplatz.
    ----------------------------
    Vielleicht überarbeitest Du den C#-Code so, dass z.B. pro Datei genau eine Klasse drin ist.
    Dann können wir uns mal ein Control rauspicken.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „RodFromGermany“ ()

    Änder doch mal deine Zeile 60 zu folgendem:

    C#-Quellcode

    1. e.Graphics.DrawImage(B, 0, 0);


    Oder noch besser:
    Mach mal folgendes in deiner Hauptcodedatei:
    Strg + H > oben (Image)B.Clone(), unten B > Alt + A
    Das entfernt alle Codestellen, bei welchen du deine Bitmap vor dem Zeichnen klonst (was unnötig ist und zu deinem Memoryleak führt).
    @Daniel Baumert Dispose in Controls wird so implementiert:

    C#-Quellcode

    1. protected override void Dispose(bool disposing)
    2. {
    3. if (disposing )
    4. {
    5. // Objekte disposen
    6. }
    7. base.Dispose(disposing);
    8. }
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!