I'm working with a transaction-based system on a Windows CE device under the Compact .NET Framework v3.5. What we've found is that as more-and-more transactions are performed, less-and-less memory is available. Obviously a memory-leak of some kind.
After each transaction, we take two memory readings; one from the OS (a PInvoke call), and one from the Garbage Collector. We've found that the OS reading is increasing memory usage, while the reading from the GC stays relatively stable (about a 1MB variance +-).
The application makes use of Microsoft Synchronization Services to store information on a couple of local databases (SQL Server Compact v3.5), and sync them with a remote server.
If this were Windows XP, I'd simply connect to the executable with WinDbg, and analyze the heap to see if I'm creating objects that are never getting GC'd. However, I don't even know if the managed heap is the problem.
So this question is two parts:
1) What are the likely culprits of leaking memory in this manner in a managed application (DataAdapters, Streams, etc)?
2) What debugging tools/techniques will help me track down the exact issue?
I know it isn't a lot to go on, but I don't have much more information than this, at this stage.
Thanks!
There are two ways to attack this. First is to look at the managed objects and their lifetimes. You can use the Remote Performance Monitor (RPM) to view snapshots of the GC heap and compare them.
You can use the CLR Profiler to inspect the call tree and see where these objects are coming from.
These two tools will usually allow you to find managed code issues.
Now, the important bit here is that you say the GC isn't reporting any growth, which tells me the GC heap is fine, and these tools are unlikely to find much in this specific case. Still, I layed out the tools because they may help you (or someone else reading this) in the future.
In your case it sounds like you have a native leak. You didn't say which type of memory is leaking - physical or virtual - but it is almost certain that something is making native allocations that aren't getting freed. SQL Compact is my guess based on what you've said about your architecture becasue the engine is implemented in native code with a managed layer that sits on top of it.
I'm also going to guess that the root cause is that you have some small managed objects (maybe a SqlCeTransaction or SqlCeCommand) that individually have a small managed footprint, but are making some native allocation for you and those objects are surviving.
The managed tools should allow you to locate a high or growing number of these items and to locate the root that is preventing the GC from killing them. Verifying that you are calling Dispose on all of the SqlCe objects you're using would be a good thing to do as well.
If all of that fails to find it, you can dive into some of the native tools, but they don't play well with managed code at all and are unlikely to give you much info.