How can I identify unwanted .NET objects that are not going to garbage?

My application (C # .NET 4.0) has been running for several days, updating the simulated account to reflect changes in prices purchased in the SQLite database.

All I need on any given date is an account in its current state and latest prices. I expect the garbage collector to keep memory usage on a fairly even keel: I see a constant increase in working set and private memory (as reported by System.Diagnostics.GetCurrentProcess() ), as well as in GC.GetTotalMemory(true) : about 300 thousand in day in this case. Inevitably, all this happens after about 12 years of modeling, after which memory usage has increased by about 1 GB.

Memory usage increases more or less linearly (much more smoothly if I press GC.Collect() at the end of each day).

I suppose that some objects are somehow not going to garbage, even if I think they will no longer need, and expected them to be cleaned in normal ebb and flow.

What can I try to determine where I accidentally managed to create such a situation?

I downloaded and launched CLRProfiler - it is going to take most of the weekend to digest the documentation, though, and there is no guarantee that it can help.

I am processing links in this question . In general, I know what situation may be causing the problem, I'm more interested in finding out if there are faster ways to identify specifics without spending precious days working through my code, bypassing links ...

NOTE. The problem is not event related and does not contain a graphical component.

+6
source share
3 answers

You said that you can simulate a workload to cause the application to crash. To quickly find a leak, simulate the workload until the memory consumption becomes significant (for example, 100 MB), attach WinDbg or VS with uncontrolled debugging to your process and run in the next 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 say that you have a problem with the int[] type. A 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 the address of your object (s). Choose one of them and run

 !GCRoot 075d1000 

And you will get the reason for your leak. You can also refer to this guide .

+7
source

Do you use events? If object A subscribes to an event on object B , then B holds a reference to A Therefore, A cannot collect garbage until B can be collected by garbage. If A unsubscribes from B , then B reference to A is deleted.

+3
source

One thing I suggest looking for as a heuristic is the place where you could attach a longer-lived instance from a shorter life to the event. If you have some kind of instance that is stored throughout the life of your application, and you have shorter classes that listen for events on it, failure to detach these events will cause your objects with a shorter period to be skipped garbage collector because a long-lasting object hangs on a link to them until you disconnect.

Edit: for what it's worth, you can check out the Ants Memory Profiler . I don’t know how this compares with the fact that you look at it, but after trying it, the learning curve on it is not so bad, so you can spend less time figuring it out.

+2
source

Source: https://habr.com/ru/post/902943/


All Articles