My (C# .NET 4.0) application runs over a period of days, updating a simulated account according to changes in prices acquired from a SQLite database.
All I need on any particular date is the account in its current state and the latest prices. I'd expect that the Garbage Collector would keep memory usage on a fairly even keel: what I'm seeing is a steady increase in Working Set and Private Memory (as reported by System.Diagnostics.GetCurrentProcess()
) and also in GC.GetTotalMemory(true)
: about 300K per day in this case. Inevitably, the whole thing crashes after about 12 simulated years, at which point the memory use has increased by about 1GB.
Memory usage increases more-or-less linearly, (very much more smoothly if I force a GC.Collect()
at the end of each day).
I'm inferring that some objects are somehow not garbage-collectible, even when I think there's no further need for them and had expected that they would be cleaned up in the normal ebb and flow of execution.
What might I try to identify where I've inadvertently managed to create such a situation?
I've downloaded and run CLRProfiler - it's going to take the best part of the weekend to digest the documentation, though, and there's no guarantee that it'll be able to help.
I'm working through the references in this question. In general, I know what kind of situation can be causing the problem, I'm more interested to see if there are faster ways to identify the specifics without spending precious days working through my code ticking off references...
NOTE: The problem doesn't appear to be event-related and there's no graphic component involved.
An object is eligible to be garbage collected if its reference variable is lost from the program during execution. Sometimes they are also called unreachable objects.
How garbage collector knows that the object is not in use and needs to be removed? Answer: Garbage collector reclaims objects that are no longer being used, clears their memory, and keeps the memory available for future allocations. This is done via bookkeeping the references to the objects.
. NET's garbage collector manages the allocation and release of memory for your application. Each time you create a new object, the common language runtime allocates memory for the object from the managed heap.
When the garbage collector performs a collection, it releases the memory for objects that are no longer being used by the application. It determines which objects are no longer being used by examining the application's roots.
You said you can simulate workload to cause your application to crash. To quickly find your leak, simulate workload until memory consumption becomes significant (e.g. 100 MB), attach WinDbg or VS with unmanaged debugging to your process and run in immediate window:
.load sos
extension C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll loaded
!dumpheap -stat
total 2885 objects
Statistics:
MT Count TotalSize Class Name
7a5eab18 1 12 System.Diagnostics.TraceOptions
(lots of unimportant stuff here)
79332b54 304 7296 System.Collections.ArrayList
79333274 56 11640 System.Collections.Hashtable+bucket[]
793042f4 345 50056 System.Object[]
79330b24 1041 99428 System.String
79332cc0 21 107109728 System.Int32[]
From this (sorted) output you can tell you are having a problem with int[]
type. Type:
!DumpHeap -type System.Int32[] (or whichever type you got)
Address MT Size
01381a1c 7931e9bc 40
(cut)
075d1000 79332cc0 67108880
03811000 79332cc0 40000016
total 22 objects
Statistics:
MT Count TotalSize Class Name
7931e9bc 1 40 System.Int32[][]
79332cc0 21 107109728 System.Int32[]
Total 22 objects
Now you have address of your object(s). Pick one of them and run
!GCRoot 075d1000
And you'll get cause of your leak. Also, you might want to consult this tutorial.
Are you using events? If object A
is subscribed to an event on object B
, then B
is storing a reference to A
. Therefore A
can't be garbage collected until B
can be garbage collected. If A
unsubscribes from B
, then B
's reference to A
is removed.
One thing that I'd suggest looking for as a heuristic is places where you might have attached to an event in a longer lived instance from a shorter lived one. If you have some instance that sticks around for the lifetime of your application, and you have shorter lived classes that listen for events on it, failing to unhook those events will result in your shorter-lived objects being skipped by the garbage collector, since the longer lived object hangs onto a reference to them until you detach.
Edit: for what it's worth, you might want to check out Ants Memory Profiler. I don't know how it compares to the one you're looking at it, but from having tried it out, the learning curve on it isn't too bad, so you might spend less time figuring it out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With