Possible memory leak
-
I have written a document imaging system in VB.Net, using Pegasus tool kit. We have over 100 client's with no problems. However our latest client is experiencing problems. They have two users and both are having the same problem. The error message is to the affect: "attempt to read or write to protected memory" This is occuring after they open and close a scaning window numerous times over the course of 30 minutes. I made sure that I disposed of all the Pegasus tools (put msgbox()) in the window's dispose method. I don't create any 'fancy' objects, although I do open file streams. But I make sure they are closed, as I do for Sqlconnections and data readers. I put a garbage collector button in the parent window: GC.Collect() GC.WaitForPendingFinalizers() GC.Collect() GC.WaitForPendingFinalizers() MessageBox.Show("Done!" + vbCrLf + _ "Memory Allocated: " + GC.GetTotalMemory(False).ToString, "Garbage Collection") I can see the memory usage going up everytime I instantiate a new window. What's interesting is that from run to run the amount reported by GetTotalMemory is always different. Does anyone have any advice as how to approach this? Are there common VB objects that need to be manually disposed of? Thanks!
-
I have written a document imaging system in VB.Net, using Pegasus tool kit. We have over 100 client's with no problems. However our latest client is experiencing problems. They have two users and both are having the same problem. The error message is to the affect: "attempt to read or write to protected memory" This is occuring after they open and close a scaning window numerous times over the course of 30 minutes. I made sure that I disposed of all the Pegasus tools (put msgbox()) in the window's dispose method. I don't create any 'fancy' objects, although I do open file streams. But I make sure they are closed, as I do for Sqlconnections and data readers. I put a garbage collector button in the parent window: GC.Collect() GC.WaitForPendingFinalizers() GC.Collect() GC.WaitForPendingFinalizers() MessageBox.Show("Done!" + vbCrLf + _ "Memory Allocated: " + GC.GetTotalMemory(False).ToString, "Garbage Collection") I can see the memory usage going up everytime I instantiate a new window. What's interesting is that from run to run the amount reported by GetTotalMemory is always different. Does anyone have any advice as how to approach this? Are there common VB objects that need to be manually disposed of? Thanks!
dBrong wrote:
I put a garbage collector button in the parent window
You really don't want to do this. Each time you call
GC.Collect()
you are freezing your applications main thread so the GC can run.dBrong wrote:
Are there common VB objects that need to be manually disposed of?
Any object that you are using that implements the
IDisposable
interface really should be cleaned up with a call toDispose()
or you should use it inside ausing
block. You specifically mention that you are opening streams and database connections, but how are you making sure that they are closed properly? If you aren't using atry/finally
or ausing
block to ensure that theClose()
orDispose()
method is being called even if an exception occurs then you aren't guaranteed that the objects will get cleaned up properly. Going beyond streams and database connections, since you are in an document imaging system, anyGraphics
objects or any image objects (Bitmap
,Image
, etc.) also should be cleaned up by callingDispose()
. These same rules apply for the Pegasus objects as well. If they aren't wrapped in atry/finally
or ausing
block there is no guarantee that they are actually being cleaned up properly.Scott Dorman
Microsoft® MVP - Visual C# | MCPD President - Tampa Bay IASA [Blog][Articles][Forum Guidelines]
Hey, hey, hey. Don't be mean. We don't have to be mean because, remember, no matter where you go, there you are. - Buckaroo Banzai
-
dBrong wrote:
I put a garbage collector button in the parent window
You really don't want to do this. Each time you call
GC.Collect()
you are freezing your applications main thread so the GC can run.dBrong wrote:
Are there common VB objects that need to be manually disposed of?
Any object that you are using that implements the
IDisposable
interface really should be cleaned up with a call toDispose()
or you should use it inside ausing
block. You specifically mention that you are opening streams and database connections, but how are you making sure that they are closed properly? If you aren't using atry/finally
or ausing
block to ensure that theClose()
orDispose()
method is being called even if an exception occurs then you aren't guaranteed that the objects will get cleaned up properly. Going beyond streams and database connections, since you are in an document imaging system, anyGraphics
objects or any image objects (Bitmap
,Image
, etc.) also should be cleaned up by callingDispose()
. These same rules apply for the Pegasus objects as well. If they aren't wrapped in atry/finally
or ausing
block there is no guarantee that they are actually being cleaned up properly.Scott Dorman
Microsoft® MVP - Visual C# | MCPD President - Tampa Bay IASA [Blog][Articles][Forum Guidelines]
Hey, hey, hey. Don't be mean. We don't have to be mean because, remember, no matter where you go, there you are. - Buckaroo Banzai
Scott, Thanks for the response. I have a couple of questions: I figure that memory usage should always be the same. However each time I start the app, and call GC.GetTotalMemory I get a different value! Are there any system calls I can make to help me find out what's really happening with memory usage? Secondly, is there a list of .net objects that explicity need dispose() to be called manually? I'll wrap the close/dispose in try/catch. I was under the impression that if it failed I'd get a runtime error? Thanks.
-
Scott, Thanks for the response. I have a couple of questions: I figure that memory usage should always be the same. However each time I start the app, and call GC.GetTotalMemory I get a different value! Are there any system calls I can make to help me find out what's really happening with memory usage? Secondly, is there a list of .net objects that explicity need dispose() to be called manually? I'll wrap the close/dispose in try/catch. I was under the impression that if it failed I'd get a runtime error? Thanks.
dBrong wrote:
Are there any system calls I can make to help me find out what's really happening with memory usage?
There aren't any system calls you can make that I am aware of. There may be some unmanged Win32 API calls, but I'm not sure. The best option to see what is happening with the GC is to use some of the performance counters that are built in. Check this post[^] on Channel 9 for more information.
dBrong wrote:
Secondly, is there a list of .net objects that explicity need dispose() to be called manually?
Unfortunately, there really isn't. The best option is to look at the following things:
- Does the object provide a
Close
orDispose
method? - Does the object inherit from
IDisposable
?
You can also look at the MSDN documentation or use Reflector to check as well. The best rule of thumb is that if the object "feels" like it should be disposed of after you're done using it, it probably implements
IDisposable
.dBrong wrote:
I'll wrap the close/dispose in try/catch. I was under the impression that if it failed I'd get a runtime error?
It all depends on how your objects (or the objects you are using) are implemented. If for some reason a disposable object were to throw an exception that was caught and eaten your calling code may not know about it and/or the call to
Dispose
may never occur. By putting the call toDispose
inside of afinally
orusing
block you can guarantee that it will get called under all conditions.Scott Dorman
Microsoft® MVP - Visual C# | MCPD President - Tampa Bay IASA [Blog][Articles][Forum Guidelines]
Hey, hey, hey. Don't be mean. We don't have to be mean because, remember, no matter where you go, there you are. - Buckaroo Banzai
- Does the object provide a
-
Scott, Thanks for the response. I have a couple of questions: I figure that memory usage should always be the same. However each time I start the app, and call GC.GetTotalMemory I get a different value! Are there any system calls I can make to help me find out what's really happening with memory usage? Secondly, is there a list of .net objects that explicity need dispose() to be called manually? I'll wrap the close/dispose in try/catch. I was under the impression that if it failed I'd get a runtime error? Thanks.
dBrong wrote:
is there a list of .net objects that explicity need dispose() to be called manually?
No, absolutely not. Such a list could never be complete, as the framework is growing with each new version, and there are thousands of thrird party libraries that contain objects that needs disposing. If in doubt, check if the object has a Dispose method. If it does, there is a reason for that. Not every class that implements IDisposable needs disposing, but unless you have determined that it's actually not needed, you should always call the Dispose method if there is one. Calling the Dispose method will not hurt even if it is not neccessary for that specific object. For example, you can close a SqlConnection object either by calling the Close method or the Dispose method, as the Dispose method makes sure that the Close method has been called. You can also call the Close method first, then the Dispose method, without harm. You can even call the Dispose method more than once on the same object without problems, you will never get an "object already disposed" error if you happen to call Dispose again.
Despite everything, the person most likely to be fooling you next is yourself.