Benutzer mit den meisten Antworten
RAM steigt in die Höhe trotz Dispose (Image/Bitmap)

Frage
-
Hallo,
ich habe eine Klasse erstellt, welche für das abspielen von MP3-Dateien zuständig ist. In dieser Klasse ist auch eine PictureBox zum darstellen der Wellenform und der Aktuellen Position der MP3 (blaue Linie, ein Pixel breit).
Gerade letzteres macht mir zu schaffen, denn das Zeichnen dieser blauen Linie lässt den RAM-Speicher in die Höhe treiben. Nach ca. 11 Stunden, sind mal eben 1,5 Gigabyte "belegt".
Ich weiß, dass es irgendwas mit dem freigeben der Resourcen zu tun hat, aber ich weiß einfach nicht wo, wie, wann?! :-(
Hier mal die eine Sub-Routine, welche für das Zeichnen der Linie zuständig ist, sobald sich die Position der MP3 geändert hat.
Public Sub DrawWaveposition(ByVal Img As PictureBox) If IsNothing(Img) Or Img.Width = 0 Or _ShowWaveform = False Then ' Es gibt kein Image, wo die aktuelle Position eingezeichnet ' werden kann. ABBRUCH! Exit Sub End If ' Position in der Wellenform berechnen Dim bitmap As Bitmap = New Bitmap(Img.Width, Img.Height) 'Dim g As Graphics = Graphics.FromImage(bitmap) Dim p As Pen = New Pen(_WaveformPositionColor) Dim bpp As Double = SoundLength / CType(Img.Width, Double) ' bytes per pixel Dim x As Integer = CType(Math.Round(SoundPosition / bpp), Integer) Using g As Graphics = Graphics.FromImage(bitmap) ' Senkrechte Linie einzeichnen If _WaveformPositionWidth = 1 Then ' Nur eine schmale Linie g.DrawLine(p, x, 0, x, Img.Height - 1) Else ' Breiter als 1 Pixel ist eine Box Dim rectBox As New Rectangle(x, 0, _WaveformPositionWidth, Img.Height - 1) g.DrawRectangle(p, rectBox) End If g.Dispose() End Using Img.Dispose() Img.Image = bitmap.Clone _WaveformSoundPosition = x p.Dispose() bitmap.Dispose() p = Nothing bitmap = Nothing End Sub
Ich habe es mit Dispose probiert, mit Using probiert, aber dennoch steigt der Arbeitsspeicherverbauch mit jedem Aufruf weiter an.
Hat bitte jemand einen Tipp für mich? Danke!
Gruß
Andy
Antworten
-
Hallo Andy,
viel hilft nicht unbedingt viel ;)
Durch das zusätzliche Clone() verbrätst Du nur weiteren Speicher.
Freigeben solltest Du das vorherige Image der PictureBox.
Aber auch Pens und andere Grafikobjekte sollten freigegeben werden.
Using führt ein Dispose aus, das braucht man also nicht nochmal.Im übrigen sollte man OrElse verwenden, denn Deine Prüfung am Anfang würde derzeit auf die Nase fallen, wenn es kein Image geben würde.
Und bitte verzichte auf diese IsNothing Funktion, Visual Basic kennt Is Nothing und IsNot Nothing und setzt die in direkte Befehle um. Eine Funktion "verbessert" da gar nichts.
Mal eine mögliche Implementation (mit einigen Annahmen bezüglich der verwendeten Variablen):
Public Sub DrawWaveposition(ByVal pb As PictureBox) If _ShowWaveform = False _ OrElse pb Is Nothing _ OrElse pb.ClientSize.Width = 0 _ OrElse pb.ClientSize.Height = 0 Then Exit Sub End If Dim imgSize = pb.ClientSize ' Die Innereien gelten als Zeichenbereich ' Position in der Wellenform berechnen Dim bitmap As New Bitmap(imgSize.Width, imgSize.Height) Using g = Graphics.FromImage(bitmap) Using p As New Pen(_WaveformPositionColor) Dim bpp As Double = SoundLength / CDbl(imgSize.Width) ' bytes per pixel Dim x As Integer = CInt(Math.Round(SoundPosition / bpp)) ' Senkrechte Linie einzeichnen If _WaveformPositionWidth = 1 Then ' Nur eine schmale Linie g.DrawLine(p, x, 0, x, imgSize.Height - 1) Else ' Breiter als 1 Pixel ist eine Box Dim rectBox As New Rectangle(x, 0, _WaveformPositionWidth, imgSize.Height - 1) g.DrawRectangle(p, rectBox) End If _WaveformSoundPosition = x End Using End Using ' Alte Grafik freigeben If pb.Image IsNot Nothing Then pb.Image.Dispose() End If pb.Image = bitmap End Sub
(Den Namen des Parameters der Methode habe ich im übrigen nur geändert damit nichts durchschlüpft).
Probiere mal damit aus, ob der Speicherverbrauch immer noch ansteigt. Wenn ja, gibt es vermutlich weitere Problemstellen.
Die Bitmap könnte im übrigen komplett entfallen, wenn man die PictureBox beerdigt; anstatt dessen ein Panel nimmt und die Linie(n) direkt darauf zeichnet.
Gruß Elmar
- Bearbeitet Elmar BoyeEditor Montag, 3. Dezember 2012 08:24
- Als Antwort markiert Robert BreitenhoferModerator Montag, 3. Dezember 2012 11:52
Alle Antworten
-
Hallo Andy,
viel hilft nicht unbedingt viel ;)
Durch das zusätzliche Clone() verbrätst Du nur weiteren Speicher.
Freigeben solltest Du das vorherige Image der PictureBox.
Aber auch Pens und andere Grafikobjekte sollten freigegeben werden.
Using führt ein Dispose aus, das braucht man also nicht nochmal.Im übrigen sollte man OrElse verwenden, denn Deine Prüfung am Anfang würde derzeit auf die Nase fallen, wenn es kein Image geben würde.
Und bitte verzichte auf diese IsNothing Funktion, Visual Basic kennt Is Nothing und IsNot Nothing und setzt die in direkte Befehle um. Eine Funktion "verbessert" da gar nichts.
Mal eine mögliche Implementation (mit einigen Annahmen bezüglich der verwendeten Variablen):
Public Sub DrawWaveposition(ByVal pb As PictureBox) If _ShowWaveform = False _ OrElse pb Is Nothing _ OrElse pb.ClientSize.Width = 0 _ OrElse pb.ClientSize.Height = 0 Then Exit Sub End If Dim imgSize = pb.ClientSize ' Die Innereien gelten als Zeichenbereich ' Position in der Wellenform berechnen Dim bitmap As New Bitmap(imgSize.Width, imgSize.Height) Using g = Graphics.FromImage(bitmap) Using p As New Pen(_WaveformPositionColor) Dim bpp As Double = SoundLength / CDbl(imgSize.Width) ' bytes per pixel Dim x As Integer = CInt(Math.Round(SoundPosition / bpp)) ' Senkrechte Linie einzeichnen If _WaveformPositionWidth = 1 Then ' Nur eine schmale Linie g.DrawLine(p, x, 0, x, imgSize.Height - 1) Else ' Breiter als 1 Pixel ist eine Box Dim rectBox As New Rectangle(x, 0, _WaveformPositionWidth, imgSize.Height - 1) g.DrawRectangle(p, rectBox) End If _WaveformSoundPosition = x End Using End Using ' Alte Grafik freigeben If pb.Image IsNot Nothing Then pb.Image.Dispose() End If pb.Image = bitmap End Sub
(Den Namen des Parameters der Methode habe ich im übrigen nur geändert damit nichts durchschlüpft).
Probiere mal damit aus, ob der Speicherverbrauch immer noch ansteigt. Wenn ja, gibt es vermutlich weitere Problemstellen.
Die Bitmap könnte im übrigen komplett entfallen, wenn man die PictureBox beerdigt; anstatt dessen ein Panel nimmt und die Linie(n) direkt darauf zeichnet.
Gruß Elmar
- Bearbeitet Elmar BoyeEditor Montag, 3. Dezember 2012 08:24
- Als Antwort markiert Robert BreitenhoferModerator Montag, 3. Dezember 2012 11:52
-
Hallo Elmar,
danke! Danke danke danke!!!! :-)
Es funktioniert auf anhieb (Routine gegen deine 1:1 ersetzt!), kein weiterer Speicheranstieg, BIS JETZT! :-)
Mehr kann ich erst sagen, wenn ich das Programm wieder über mehrere Stunden laufen lasse.
Aber jetzt steigt der Arbeitsspeicher nicht mehr nach jedem "Sprung" im Song um mehrere MB!!! Es kommt NICHTS mehr hinzu, noch nicht mal ein KB :-)Der Anstieg ist zwar noch vorhanden, aber erst wenn der nächste Song geladen wird. Ich gehe mal davon aus, dass in der Routine (erstellen der Wellenform) das "gleiche Problem" ist und das werde ich, dank deiner Vorlage, noch rausfinden :-)
Vielen Dank nochmal! :-)
Gruß
Andy
PS: Natürlich habe ich meine "alte Routine" behalten um zu sehen/zu vergleichen wo mein Denkfehler ist/war :-)