You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardexpand all lines: doc/.NETMemoryPerformanceAnalysis.md
+15-8
Original file line number
Diff line number
Diff line change
@@ -1070,11 +1070,15 @@ The GCStats view has a convenient rollup table at the top of each process that s
1070
1070
1071
1071
For gen2 GCs, we’d like to see most or all of them done as BGCs. But if you do see a full blocking GC (denoted as 2N in GCStats), chances are its pause time is long if your heap is big (you will see gen2 GCs have very high Promote MB compared to ephemeral GCs’). Usually what folks do at this point is to take a Heap Snapshot to see what’s on the heap and try to reduce that. However the first thing to figure out is why you are doing full blocking GCs in the first place. You can check the Condemned Reasons table for this. The most common reasons are [high memory load](#GC-is-per-process-but-is-aware-of-physical-memory-load-on-the-machine) and [gen2 fragmentation](#How-often-GCs-are-triggered). To find out the memory load that each GC observed, click on the "Raw Data XML file (for debugging)" link right above the "GC Rollup By Generation" table in the GCStats for that process and it will generate an xml file that includes additional information including memory load. An example is (I trimmed away most of the info) -
This says when GC#45 happened it observed a memory load of 47%.
1078
1082
1079
1083
##### Long pause due to bugs
1080
1084
@@ -1094,21 +1098,24 @@ If you see ephemeral GCs suddenly promote a lot more, then it’s expected that
1094
1098
1095
1099
I’m not aware of any other tools that would tell you this info conveniently (if you know of any tool that tells what old generation objects hold onto young gen objects that make them survive during a GC, please kindly let me know!).
1096
1100
1097
-
Note that if you have an object in gen2/LOH that holds references of young gen objects and if you don’t need them to refer to those objects anymore, you’ll need to manually set those reference fields to null. Otherwise they will [continue to hold those objects live and cause them to be promoted](#1-The-generational-aspect). For C# programs, this is a main reason that causes ephemeral objects to survive (for F# programs, not so much). You can see this from the Raw XML generated by the GCStats view (click on the "Raw Data XML file (for debugging)" link right above the "GC Rollup By Generation" table) and I trimmed most attributes away from the xml:
1101
+
Note that if you have an object in gen2/LOH that holds references of young gen objects and if you don’t need them to refer to those objects anymore, you’ll need to manually set those reference fields to null. Otherwise they will [continue to hold those objects live and cause them to be promoted](#1-The-generational-aspect). For C# programs, this is a main reason that causes ephemeral objects to survive (for F# programs, not so much). You can see this from the Raw XML generated by the GCStats view (click on the "Raw Data XML file (for debugging)" link right above the "GC Rollup By Generation" table) and I trimmed most attributes away from the xml -
How many bytes promoted by each GC thread due to various kinds of [roots](#What-makes-an-object-survive) are part of the <PerHeapHistory> data (MarkStack/FQ/Handles are marking stack variables, finalize queue and GC handles respectively). One of the perf improvements for [Server GC](#Server-GC) we made in .NET 5 is to balance work on the GC threads when we mark the OldGen roots since this usually causes the largest promotion amount. So if you see this number very unbalanced in your app, upgrading to .NET 5 would help.
1118
+
How many bytes promoted by each GC thread due to various kinds of [roots](#What-makes-an-object-survive) are part of the PerHeapHistory data -MarkStack/FQ/Handles are marking stack variables, finalize queue and GC handles respectively and MarkOldGen indicates the number of bytes promoted due to references coming from older generations. So for example, if you are doing a gen1 GC, this is how much gen2 objects holding onto gen0/gen1 objects to make them survive. One of the perf improvements for [Server GC](#Server-GC) we made in .NET 5 is to balance work on the GC threads when we mark the OldGen roots since this usually causes the largest promotion amount. So if you see this number very unbalanced in your app, upgrading to .NET 5 would help.
1112
1119
1113
1120
#### **Figuring out if the long GCs are due to GC work or not**
0 commit comments