GC开始和停止事件

8

当GC开始时,是否有可能获得事件? 我想计时每个单独的GC,以便我可以确定服务器中的暂停是由于GC还是其他原因。

GC在运行时会暂停所有.NET线程,对吗?(除了它运行的线程,当然)。未托管的线程呢?

谢谢!


谢谢您的评论,回复得真快 :-) 我已经寻找答案有一段时间了,所以我已经知道这些建议(前三个评论)。我想在时间轴上显示GC何时运行以及何时不运行。因此,知道它何时完成,或者自上次收集以来使用了多少时间,是不够的。我很惊讶我还没有找到解决方案,但如果没有任何现成的工具,我将尝试编写自己的hax0r工具来实现它。再次感谢! - Rabbit
7个回答

6
如果您只想弄清楚何时运行GC,有一个更简单的方法。它不会告诉您确切的开始时间,也不会在结束时完全告诉您,但是如果您可以在服务器上注意到暂停时查看此处描述的方法的输出,您应该能够确定GC是否是您的问题。
基本上,您需要创建一个带有终结器的类,构造该类的对象,然后仅丢弃引用(即不存储它)。然后,对象将一直保留,直到GC命中它,然后将被终止。
现在的技巧在于,在终结器中记录(以任何您要使用的方式)已运行终结器,并且除非应用程序域正在关闭过程中,否则只需构造一个新对象,然后立即丢弃对其的引用,为下一个GC做好准备。
这种方法效果惊人,您不需要做太多工作。
以下是我使用的类:
namespace PresentationMode
{
    /// <summary>
    /// This class is used to get a running log of the number of garbage collections that occur,
    /// when running with logging.
    /// </summary>
    public sealed class GCLog
    {
        #region Construction & Destruction

        /// <summary>
        /// Releases unmanaged resources and performs other cleanup operations before the
        /// <see cref="GCLog"/> is reclaimed by garbage collection.
        /// </summary>
        ~GCLog()
        {
            SiAuto.Main.LogMessage("GARBAGE COLLECTED");
            if (!AppDomain.CurrentDomain.IsFinalizingForUnload() && !Environment.HasShutdownStarted)
                new GCLog();
        }

        #endregion

        #region Public Static Methods

        /// <summary>
        /// Registers this instance.
        /// </summary>
        public static void Register()
        {
#if DEBUG
            if (SiAuto.Si.Enabled)
                new GCLog();
#endif
        }

        #endregion
    }
}

您只需要调用.Register()方法即可。请注意,这里我使用SmartInspect作为我的日志工具,所以您需要将涉及SiAuto的调用替换为其他内容。

在另一个项目中,同样使用SmartInspect,其中有“观察”(watches)的概念,您可以发送数值,并在日志工具中绘制它们的图形。我连续发送了0、1和0这些数值,这样就可以得到一条始终保持在0L的图形,但每次GC运行时会产生一个尖峰。再加上一个监视CPU使用率和内存使用情况的后台线程,就可以获得非常好的数据。


3
这就是性能分析 API 的用途。请参见 ICorProfilerCallback2::GarbageCollectionStartedGarbageCollectionFinished
作为一个性能分析器,显然不适合在生产系统上进行常规使用。但听起来你主要是出于诊断目的而感兴趣。因此,值得检查一下商业性能分析器是否已经提供了这个功能,或者 perfmon 计数器是否足够 - 编写自己的性能分析器可能是一个非常复杂的解决方案!

这正是我一直在寻找的!这主要是一个业余项目,所以“非常笨重”的解决方案听起来不错(直到我感到无聊并找到新的个人项目为止 :))谢谢! - Rabbit

1

1

垃圾回收器不会发出任何事件,但您可以使用计时器并调用 GC.CollectionCount() 来查看何时发生了回收操作。


0

您可以使用CLR Hosting准确地监测和测量GC暂停。您可以在此文章中找到一个关于如何准确测量GC暂停的示例:准确测量GC暂停


0

非托管线程不受GC影响。

您可以在性能监视器中查看GC性能,这里有一篇关于如何创建系统监视器的文章。我认为您可以以某种方式获取到GC的计数器。

Codeproject

这是GC使用的性能计数器的描述。

GC counters


0

GC时间性能计数器应该为您提供所需的数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接