Tracking down the source of .NET 4.0 Induced GC

2019-07-07 01:44发布

问题:

I'm using PerfMonitor.exe ( http://bcl.codeplex.com/wikipage?title=PerfMonitor ) to track down some .NET performance issues of a .NET 4.0 app that uses some third party libraries some of which are native code.

When I run the Perfmonitor GCTime report, it lists the individual GC's and classifies them in several ways. One column in the report is called "Reason". Some GC's have Reason="Induced" and others have Reason="SmallAlloc".

I assume that the GCs labelled "SmallAlloc" are caused by regular allocation (New Object()) and GCs labelled "Induced" are caused by a call to "System.GC.Collect". Please let me know if you think I've made an incorrect assumption.

I'm trying to find the code that is calling System.GC.Collect but I've been unsuccessful. Using MSVS 2010 Professional, I set up a breakpoint in System.GC.Collect, and made sure that this breakpoint works by writing a simple test function that contains a call to System.GC.Collect. However, my app that I'm tuning does not break at that breakpoint which makes me believe that none of the code calls System.GC.Collect.

I'm thinking maybe there is native code that induces the GC by calling a native function in mscorwks.dll directly and bypasses System.GC.Collect. I see that System.GC.Collect calls _Collect in JitHelpers.cpp which is in mscorwks. Is there a way to set a breakpoint in that function?

回答1:

I looked a little closer at the output of PerfMonitor.exe. I'm not sure that every GC labelled "Induced" is actually induced by System.GC.Collect. It appears that all Gen 1 GC's are labelled Reason="Induced", while all Gen 0 GC's are labelled Reason="SmallAlloc". Gen2 GCs are labelled Reason="LowMemory".

There is a performance counter for tracking .NET Induced GCs. I monitored that performance counter and it does not show any induced GC's in my process. So I conclude that Perfmonitor.exe has misled me.



回答2:

It seems you've deduced that GC.Collect() is not your issue here, but for reference, I have succeeded in putting breakpoints in GC.Collect in the past when I could see from the Induced GC counter that there were definitely induced GCs happening.

You can set the breakpoint location to System.GC.Collect and give it a go. Using this tactic, I'm sometimes successful in setting Framework breakpoints, sometimes not. I don't know if it's because methods/property calls are optimised out, or some other reason. But it's always worth a try. You may have to do things such as disabling "Just My Code" in the Tools->Options->Debug section.