Comments
3 comments
-
Hi there, I'm so sorry to say that there isn't a way to stop the profiler from forcing a full gc on the memory snapshots (the developers have chosen this behavior so that the results focus on objects that can't be collected by a GC).
Regarding this memory issue you're seeing though, do you by any chance call on GC.Collect manually from your code? One possible reason for this behavior is if a manual call is forcing Gen 1 objects into Gen 2 prematurely.
If not though, can I just confirm-- if you enable the "Gen 2 heap size" counter and then take a snapshot to force a GC as soon as the previous GC promotes the bunch of objects to Gen2, do they immediately get get picked up by the GC or do they actually stay in memory for a bit longer? And do you see large spikes/drops for the Gen 2 heap counter in the timeline?
Thanks! -
I don't manually call GC anywhere in our code. We do have a hook to do that, but only for memory debugging purposes.
I do see large spikes in the Gen 2 Heap Counter
The objects tend to stay in memory a bit longer, but not much. Many of them are replaced every couple of seconds. -
Ah okay, thanks very much for those details!
As I think about this more, if only a gen1 GC is getting triggered, that means that gen1 is reaching its threshold. .NET changes this threshold constantly, but I'm wondering if at the point in your application right before the gen1 GC happens, if the gen1 heap is usually around the same size?
If there is an expected threshold, you can then take a snapshot when the gen1 heap nears that size, before the gen1 GC actually gets triggered. Then it may be useful to see which objects were promoted to gen2 (by the full GC) to see why they are still in memory and perhaps if the gen1 heap is unnecessarily getting filled up. (And if this is possible, you can then take a second snapshot to clean up gen2 and see which classes decreased in size --that may also help narrow down the issue to a particular class.)
Can I also just check if you may be using a lot of finalizable objects? That could mean that objects are still promoted to the next generation even though they are on they are no longer needed (and then the next GC or two usually cleans them up). When you take snapshots with the profiler, (although most of the gen2 objects are getting cleaned up), do you generally see a lot of objects in the class list if you enable the "kept in memory exclusively by GC Root of type finalizer queue" filter? Or if you add a customer performance counter to the timeline to monitor "Promoted Finalization-Memory from Gen 0" (I believe this actually includes memory promoted from both gen0 and gen1), is this usually quite high after a garbage collection?
Add comment
Please sign in to leave a comment.
In production these collections are taking 5-6 seconds and causing usability issues with our application, so it's imperative that we address them.