tags:

views:

338

answers:

5

My application has just leaked 1.5GB of memory. I guess since I don't have a ton of data available to me, I'm assuming that it's leaked the memory, but it could also just be holding onto it.

I'm currently using perfmon to gather as much information as I can, to try to understand what could be causing the problem. I don't have a whole lot of leads at this point, and was hoping to get more hints from people here.

  1. The first thing I can say is that I do not implement IDisposable in any of my classes. However, I know I do not call Dispose on any of the GUI elements, like SolidColorBrush. As my app isn't graphics-intensive by any means, I figure this can't be causing the problem. However, I will add the necessary calls.

  2. I don't know if I'm using any other classes in the framework that implement IDisposable. I read a post here on SO about FxCop. I installed and used it to analyze my assembly, but it seems to only check for my own classes' correct implementation of IDisposable. Is there another tool that can tell me ALL classes that implement IDisposable?

  3. I'm currently using WF in my application, and WFs are constantly being launched and finished. Perfmon shows that WFs are ending properly, and I am using the "using" keyword, which I understand deals with proper disposal for me.

  4. Is there a simple way to tell if the memory being "leaked" is from unmanaged or managed code?

  5. The app was using 77k+ handles at the time I got the OOM exception.

Any tips on how to proceed next would be greatly appreciated. I am planning on running the app again and monitoring the performance counters, and maybe stubbing out certain calls. I can also run the simulation for comparison's sake, since in that mode it won't call into my C DLL.

A: 

Use CLR Profiler to figure out what you're leaking. Then fix it.

Craig Stuntz
I just posted a comment to my question a few minutes ago -- the CLR Profiler doesn't seem to be working properly. It launches my application, but then just sits there waiting for the CLR to launch, apparently.
Dave
+1  A: 

Red-Gate has a memory profiler (http://www.red-gate.com/products/ants_memory_profiler/index.htm) that is extremely useful for these sorts of things. I highly recommend it. 30 day trial.

Randy

Randy Minder
Cool, I will install it next. I had SciTech's profiler on there originally. I did ask Red Gate a few weeks ago for a personal demo, but they declined. :) Guess I'll roll up my sleeves and try that next.
Dave
+4  A: 

Tess Ferrandez has a number of blog posts that could be of interest to you.

Also ANTS Memory Profiler is a great tool for finding leaks.

Jonas Elfström
reading them now! :) thanks!
Dave
Problem is not yet 100% solved, but this answer came the closest and provided a ton of useful info for me to research and learn about very relevant subjects. This was great!Using ANTS, I was able to narrow the leak down to the creating of the WorkflowRuntime. Even though I created the runtime with "using(WorkflowRuntime wr = new WorkflowRuntime()) {}", it's leaking huge amounts of memory each time. According to a bunch of search results, this bug was supposed to have been fixed by now. My current "solution" for testing purposes only is to use a singleton.
Dave
The singleton is not 100% correct IMO, because I need to be able to differentiate between different workflows. I am running up to 8 simultaneously, and if any of them encounters an error, I need to know which one. How can you determine which WF had the error? Perhaps that is the topic of another question. :)
Dave
http://msmvps.com/blogs/omar/archive/2009/03/14/memory-leak-with-delegates-and-workflow-foundation.aspx had a similar problem.
Jonas Elfström
+2  A: 

Before you go and invest in tools, you should try to find out what is leaking...

You already attached perfmon, and that is great. I would monitor the following perfcounters.

Process\PrivateBytes process\Handle Count Process\NonPagedPool

.NET CLR Memory*

If your private bytes is growing, as well as .NET CLR Memory\BytesInAllHeaps, it points to a managed leak. NEXT STEPS: Take a process dump and analyze using CLR Profiler, or alternately, attach windbg.exe to the process, load the sos extension dll, and analyze your managed heap for leaks.

IF private bytes is growing, without a corresponding increase in .NET CLR Memory* counters, then it points to an unmanaged leak. You will have to attach windbg.exe to the process and use the !heap extension to examine the process heaps.

If you are seeing a monotonically increasing HandleCount as well as NonPagedPool, then you have a handle leak - this can be in managed code, or native code. You will have to figure out which handles are leaking - you can use processmon.exe from sysinternals to get a list of handles,and investigate further.

Hope this helps.

feroze
Unfortunately, I did close the app already so I could try profiling, but I did check the Private Bytes value and it was l.5GB. I did not add the NonPagedPool, unfortunately. BytesInAllHeaps was also 1.5GB. Thanks for the useful info!
Dave
Ok, so now I know that it's definitely coming from my workflow. I'm creating the runtime with using {}, then calling CreateWorkflow and passing it a new instance of my sequential workflow. If I was smarter when I first wrote this code, I would have made the workflow runtime a singleton, rather than instantiating a new one each time. I'll do that first and see what happens. But still, even if I did this, shouldn't using{} have called Dispose for me???
Dave
Whoops, and to clarify, I think I should create pool of WF runtimes, as I'll definitely need more than one at once.
Dave
Yes, disposing the WF runtime helps, but you still dont know what is leaking. If the GC heap is also at 1.5g, then you will need to use the techniques I described. Either take a process dump or debug the process live, using Windbg + SOS extensions. Or you can attach .NET CLR Profiler to the process and have it dump out your object allocations. And see what objects are not being collected, and who their root is, etc.
feroze
A: 

Not directly answering your question, but I always use Process Explorer which shows process Virtual Size, Working Set, Gen 0,1 and 2 Collections and private Bytes (related to unmanaged memory). Basically it's just a nice UI for regular windows Tasks Manager, and performance counters. Can help you observe the memory-related behaviour of your application.

Bolek Tekielski
that's what I use perfmon for, which will give you the same information, and it's built into windows already. It's just not pretty, but the report view works quite well IMO.
Dave