Memory leak
-
Hi all,
I am trying to rotate an image in a picturebox with images from resources.
I have 20 images which I swap every 50 ms.
I do that like this:
Private Sub ChangeLogo()
Dim logo As Image
Dim logonumber1 As New System.Text.StringBuilder
Do
logonumber1.Remove(0, logonumber1.Length)
logonumber1.Append("Logo")
logonumber1.Append(k.ToString.PadLeft(2, "0"))
logo = CType(My.Resources.Resources.ResourceManager.GetObject(logonumber1.ToString), System.Drawing.Bitmap)
PictureBoxVisible(Me.PictureBox2, logo)
Thread.Sleep(50)
k += 1
k = k Mod 20
Loop
End Sub
the problem is in the red colored line of code, that part is making the system consume memory until it runs out and exits with memory exception unhandled.
Does anyone have any idea how to do that so it doesn't consume that much memory???
Thanks,
Grega
-
Assuming you do not run out of memory the first time the line in red is run, try adding this line before it:
logo.dispose
You may need to set the picturebox to be empty first.
-
Hi,
thanks for reply.
No I don't run out of memory for a while but after a while, when images in a picturebox already come around for a few times.
I put the logo.dispose before and emptied the picturebox before like this...
'*****************************
PictureBoxEmpty(Me.PictureBox2)
If Not (logo Is Nothing) Then
logo.Dispose()
End If
logo = CType(My.Resources.Resources.ResourceManager.GetObject(logonumber1.ToString), System.Drawing.Bitmap)
PictureBoxVisible(Me.PictureBox2, logo)
'*****************************
Private Delegate Sub PictureBoxEmptyDelegate(ByVal Pbx As PictureBox)
Dim PictureBoxEmpty1 As PictureBoxEmptyDelegate
Private Sub PictureBoxEmpty(ByVal Pbx As PictureBox)
If Me.InvokeRequired Then
PictureBoxEmpty1 = New PictureBoxEmptyDelegate(AddressOf PictureBoxEmpty)
Invoke(PictureBoxEmpty1, Pbx)
Else
Pbx.Image = Nothing
End If
End Sub
'********************************
but it doesn't help...I guess after a while garbage colector frees all the old logo objects, but that doesn't happen fast enough.
Anys other ideas?
Thanks
Grega
-
You added this code
If Not (logo Is Nothing) Then logo.Dispose() End If
But is 'logo' still a local variable or did you change it to a global one? This code won't do anything if 'logo' is still local because 'logo' wouldn't maintain a reference to the last image it pointed to. Try making it global if it isn't and see what happens. You could also try loading the imgages into an array ahead of time. Instead of createing a new image each time from the resources and presumably requiring more and more memory, you would store all the images you'll need in an array. Now you don't have to create a new instance of a image every 50 ms, you just need to grab the appropriate reference when they are needed. -
I ran a little test. Basically what I did was try to simulate your scenerio. I had a timer fire off every 50 ms. When it fired it created a new instance of an image (it picked a file on my HD at random) and assigned it to a picturebox. I watched my availalbe memory by bringing up the task manager. Available memory would continue to drop upto about 300-400 mB at which point it appeared the garbage collector ran and it would jump back up. It cycled like this for as long as my test ran.
I had about a 1 gig of free memory so my system could handle it but obviosly this isn't a good thing. I then added one line of code. Before I assign the image to the picturebox I call the dispose method of the image in the picturebox. It looked like this.
If PictureBox1.Image IsNot Nothing Then PictureBox1.Image.Dispose() PictureBox1.Image = Image.FromFile(file)
After doing this memory usage stopped fluctuating. So my test shows calling the dispose method for the image should solve the problem. So either make sure 'logo' is declared globally and thus remembers it's reference to the last image you created or get the image reference by using Picturebox1.image and call the dispose method when your done with it.
**EDIT**
I noticed in your procedure 'PictureBoxEmpty' you set the image = nothing. This puts you at the mercy of the garbage collector. Whenever you want to free a resource immediatly you should call it's dispose method. Basically if your done with an object and it has a dispose method you should always call it. Assuming you are calling PictureBoxEmpty before assigning the new image you should be able to fix the memory leak just by changing pbx.image = nothing to pbx.image.dispose
-
Hi,
Thanks a lot for your reply TwoFaced. That made few things more clear to me! :)
the thing is that I think that unstopable consumtion of has now stoped. (the whole think is in my case even more problematic becouse this is application for embedded system, so I am very limited with memory I have something like 14mb free)
I used the first solution, declared logo as global and disposed it before setting a new image to it, becouse the second I cannot make it work I tried like this:
Dim PictureBoxVisible1 As New PictureBoxVisibleDelegate(AddressOf PictureBoxVisible)
Private Sub PictureBoxVisible(ByVal ctr As Control, ByVal img As Image)
If ctr.InvokeRequired Then
BeginInvoke(PictureBoxVisible1, ctr, img)
Else
Dim pbx As PictureBox
If TypeOf (ctr) Is PictureBox Then
pbx = ctr
If pbx.Image IsNot Nothing Then pbx.Image.Dispose()
pbx.Image = img
End If
ctr.Visible = True
End If
End Sub
but in a few repeats I get ObjectDisposedException was unhandled! message.
I think that memory still rises till it loops trough all the images and then stops?!(EDIT:memory goes up by 64KB for a while) but I'm not sure. Since I am doing all this in non GUI thread and I am accessing the control on the form trough the delegate, do you think that the way I do that could be a problem to?
Thanks for all your help!
Grega
-
I don't think threading should be a problem. I set up the scenerio again only this time I used a thread like you. I wasn't able to re-create your error and memory usage seemed reasonable. My system was fluctuating by about 5-10 MB while the application was running but it would also do this at times when the application wasn't running. So it's hard to say what additional memory usage my demo actually used.
If memory is only going up 64 KB then that's hardly worth a concern. Even with a limited environment of 14 MB that's not very much. Plus some memory has to be used becaues you have an image in memory all the time.
As for the error I had a few guesses as to why that might occur and tried to recreate it but I just couldn't. Try changing BeginInvoke to Invoke. It's worth a shot but in my test either worked fine. Also take a look at the code I used and see if you can figure out any possible differences.
Public Class Form1 Private th As System.Threading.Thread ' Start the logo animation Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click th = New System.Threading.Thread(AddressOf ChangeLogo) th.Start() End Sub ' Stop the logo animation Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click th.Abort() End Sub Private Sub ChangeLogo() Do Dim logo As Image = GetNewImage() SetPBImage(PictureBox1, logo) Threading.Thread.Sleep(50) Loop End Sub Private Delegate Sub SetPBImageDelegate(ByVal pb As PictureBox, ByVal logo As Image) ' Sets the image for a given picturebox in a thread safe manor Private Sub SetPBImage(ByVal pb As PictureBox, ByVal logo As Image) If pb.InvokeRequired Then pb.BeginInvoke(New SetPBImageDelegate(AddressOf SetPBImage), pb, logo) Else ' Dispose of the previous image so resources are freed immediatly If pb.Image IsNot Nothing Then pb.Image.Dispose() pb.Image = logo End If End Sub Private rnd As New Random ' Returns a random image from a directory Private Function GetNewImage() As Image Dim files As String() = IO.Directory.GetFiles("c:\logos", "*.jpg") Dim file As String = files(rnd.Next(0, files.Length)) Return Image.FromFile(file) End Function End Class
With my code I get a random image from the hard drive. I don't think this should make a difference.
**EDIT**
If you are still having troubles post all the code that handles changing the logo and I'll see if I can spot a problem. -
Hi,
Thanks for all this Two faced... helped me a lot.
I managed to clear most of the memory leak now. those 64K changed into around 16K per day...so it is much better but still since this will be application that will need to run not for few days but few years this is still quite an issue.
I am doing a lot of testing by letting application run for long time few days, and everytime I exclude something
In code I pasted below is where I write some data into some text file... this is done every 2,5 minute by calling all three in a sequent order:f.OpenFile()
f.WriteDataToFile(data.ToString)
f.CloseFile()Does anyone think this could be the problem for the small leak I am still having...(leak goes up by 4K)
Thanks a lot for your help,
Grega
Public Sub OpenFile() 'ByVal path As String
Dim path As String = DiskPath & "\" & "File_" & Format(Now, "yyyyMMdd") & ".txt"
'Dim path As String = "C" & "\" & "File_" & Format(Now, "yyyyMMdd") & ".txt"
fs = New FileStream(path, FileMode.OpenOrCreate, FileAccess.Write)
s = New StreamWriter(fs)
End Sub
Public Sub CloseFile()
s.Close()
fs.Close()
s = Nothing
fs = Nothing
End Sub
Public Sub WriteDataToFile(ByVal data As String)
s.BaseStream.Seek(0, SeekOrigin.End)
s.WriteLine(data)
End Sub
Post a reply
Quick links
Recent activity
- arif ahmad replied to How to receive data in web ...
- William Thompson replied to What is the name of the Win...
- Sameera Piyadigamage replied to Point of Sale Developers: H...
- Scott Carline replied to 4 x C# Developers for large...
- Rajendra Dhakal replied to Restore SQL Server text dat...
- cloud rainda replied to How to convert between TS f...
Enter your message below
Sign in or Join us (it's free).