|
-
August 9th, 2005, 08:01 AM
#1
Memory Leak in C#???
I am having a problem with memory in a windows service I created in c# vs2003. The service activates once a day and performs a large operation. Using the resource monitor I can see the service grow to several hundred megabytes which it does not release.
The service contains a timer which fires an event once a minute. That event calls a function called Harvest() every 24 hours. Several classes are called in Harvest which populate many ArrayLists, hence the size of the service. However, all these classes are declared locally within the scope of Harvest(). So when Harvest completes, they go out of scope, and the garbage collector should kick in within a reasonable amount of time.
The service ran at 2:00am and this morning at 9 the memory footprint was still several hundred megs. I've tried forcing the local variables to null, called GC.Collect(), even GC.ReRegisterForFinalize(object). Nothing worked.
None of the code called is unmanaged. Havest() locally instantiates wrapper classes around the SharePoint Portal 2003 object model, which is written in .NET. Obviously something is amiss with this but I can't figure out why when it goes out of scope it won't clean itself up. There are several Close() methods for some SharePoint objects, but calling them makes no difference (as this happens automatically when they go out of scope). I can even issue an iisreset which kills SharePoint but the memory footprint does not change.
Has anyone encountered a similar problem or used tools compatible with C# which could help?
Right now I am wishing I was writing in C++!
-
August 9th, 2005, 08:20 AM
#2
Re: Memory Leak in C#???
C#'s variables dont get destroyed when it leaves scope (neither does a new obj in C++ btw).
a good rule of thumb is, if it has a Dispose method, invoke it *as soon* as you're done with it.
the more you mess with the gc the less likely its going to work correctly for you. if you dispose items when you're done, you'll keep things in check.
-
August 9th, 2005, 08:28 AM
#3
Re: Memory Leak in C#???
A new'ed obj in C++ requires a delete. A local object in C++ calls its destructor when leaving scope. Unless I misunderstand the garbage collector completely, if its declared locally in a function and the function exits the reference goes to 0 which marks it to be cleaned up.
As I mentioned already, I have called Close() (which in turn calls Dispose) for all the SharePoint objects which have that method.
Lastly, I'm not messing with the GC because that's the way I designed the program. I'm merely attempting a few things because of the problems I encountered leaving the GC to its own devices.
I'd appreciate some helpful advice.
-
August 9th, 2005, 09:43 AM
#4
Re: Memory Leak in C#???
sorry I wasnt helpful. I'll remember to keep to myself next time.
-
August 9th, 2005, 10:06 AM
#5
Re: Memory Leak in C#???
No worries, my fault for only posting here when I'm frustrated. Its hard to tell who is a newbie sometimes.
Here is the solution, for better or worse this resets the memory footprint. I run the following at the end of the Harvest() function when the locally instantiated SharePoint wrappers go out of scope.
Code:
//For the sake of the memory footprint in Task Manager
GC.Collect();
System.Diagnostics.Process.GetCurrentProcess().MaxWorkingSet = System.Diagnostics.Process.GetCurrentProcess().MaxWorkingSet;
Last edited by Chris Green; August 9th, 2005 at 10:10 AM.
-
August 9th, 2005, 10:46 AM
#6
Re: Memory Leak in C#???
Is the parent app still running even though Harvest is not? Perhaps Windows, in the interest of VM efficiency, retains handles to the memory in case you might want to access the same thing again, as long as NEWER demands are not made for the same memory. Just an odd thought.
-
August 9th, 2005, 11:12 AM
#7
Re: Memory Leak in C#???
 Originally Posted by Chris Green
A new'ed obj in C++ requires a delete.
Yes but in most cases you won't wright it on your own 
Code:
void foo ( void )
{
auto_ptr<MyClass> myObj ( new MyClass );
// Do something with myObj, and let auto_ptr delete the object
}
-
August 9th, 2005, 11:32 AM
#8
Re: Memory Leak in C#???
Unless I misunderstand the garbage collector completely, if its declared locally in a function and the function exits the reference goes to 0 which marks it to be cleaned up.
Firstly, the GC doesn't work by a reference count approach. It uses a broader approach to mark memory for release.
Secondly memory is only released when the GC has to. Which is why it appears to build up to an absolute maximum and then drops down.
It doesn't release memory immediately : it waits until it's got lots of memory to be released and then does it in one block.
Thirdly, the GC likes lots of little classes rather than a few big ones. It assumes larger classes will survive longer than smaller ones (or something like that). I've written about this before and it's one of my likes about C# : good object orientation is rewarded by faster running and smaller footprint exes than bad object orientation.
GC.Collect() has been put into the framework for the very reason that you've found : i.e. when you need to force the GC to do its garbage collection at a specific point. Personally I've never had to use it : and I've written some very large apps in my time with C# with a lot of memory allocations.
Darwen.
-
August 9th, 2005, 03:29 PM
#9
Re: Memory Leak in C#???
What does the footprint look like if give the process a bikini wax with SetProcessWorkingSetSize()? This will give you a better look at your mem consumption.
Regards.
-
August 11th, 2005, 05:15 AM
#10
Re: Memory Leak in C#???
Okay, I've just looked up how the GC works, and here it is in a nutshell (for completeness).
Reference counts are NOT used. The main reason for this is because you can end up with circular references (e.g. in linked lists etc).
A concept of "roots" is employed. This states that you can determine all used references in the system by considering
(1) All global/static variables.
(2) All local references to memory at the current point of execution.
(3) All references to memory held in the CPU registers.
(4) References to objects in the Ready To Finalize list.
When performing garbage collection, the GC first assumes that all memory on the heap (i.e. dynamically allocated) is garbage.
Then it runs through the above 4 "roots" finding objects which are still active.
After this, it knows what memory is garbage and releases it.
In addition, there is the concept of "generations" in the GC. There are 3 generations :
Generation 0 : Objects which haven't gone through a GC cycle yet.
Generation 1 : Objects which have gone through a single GC cycle and survived.
Generation 2 : Objects which have gone through more than one GC cycle and survived.
Memory is taken from the lowest generation first : therefore once all the memory in Generation 0 has been used, the memory in Generation 1 is garbage collected and used. Likewise for generation 2.
Therefore long-lasting memory is less likely to be released than short-lasting memory. Which is probably what is happening in your case.
To explicitly mark an object for release, set the variable reference to "null" i.e.
Code:
byte [] abChars = new byte[1000];
abChars = null; // explicitly mark the memory for release
Darwen.
Last edited by darwen; August 11th, 2005 at 05:19 AM.
-
March 9th, 2006, 11:53 AM
#11
Re: Memory Leak in C#???
Very nice insight in this post. I am making the switch over from C++, so I am having to relearn how to handle memory in C#.
In C++, I make a habit of checking for valid pointers before using them...
Code:
CMyClass* pClassPointer = NULL;
pClassPointer = new CMyClass();
if(pClassPointer == NULL)
{
ASSERT(FALSE);
return FALSE;
}
pClassPointer->m_intMember = 7;
delete pClassPointer;
pClassPointer = NULL;
return TRUE;
The above code is safe way (I've found) to use pointers.
My question is, do the same rules apply in C# for reference types? That is... if I use a reference type, should I first check to see if its null, and then when I'm done, should I set it to null (the equivalent of delete i C++)? In doing this, do I expel the risk of a memory leak?
-
March 9th, 2006, 12:10 PM
#12
Re: Memory Leak in C#???
.net is pretty good w/ memory management. not everything is managed though. so the best practice is to call the Dispose method on objects implementing IDisposable (if there isnt a public Dispose method on the IDisposable object, setting it = null will do the same thing as calling the dispose method) when youre done with it.
-
March 9th, 2006, 12:15 PM
#13
Re: Memory Leak in C#???
Why wouldn't you just derive every user-defined class from IDisposable and Dispose() of all reference type variables as soon as you are finished? Wouldn't this be the safest and most memory efficient method?
-
March 9th, 2006, 12:42 PM
#14
Re: Memory Leak in C#???
most classes are purely managed by the built in garbage collector. objects that are unmanaged or interop w/ unmanaged code should use the disposable interface for that, so that their unmanaged resources can be "deleted." managed objects are allocated & managed in the gc heap, but some of what they use might be allocated in unmanaged memory, so while the object that contains references to the unmanaged objects might be deleted, the actual items in unmanaged memory will be left orphaned. with the managed items, finializing them is a matter of timing more than anything else. Dispose is the 'do it now' directive. if that object has unmanaged items, then they are cleaned up then. otherwise the object will be cleaned out at some later time.
Last edited by MadHatter; March 9th, 2006 at 12:46 PM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|