是否可以记录垃圾收集的对象数量?

时间:2012-06-23 07:56:58

标签: c#

我正在撰写HFT交易申请表。我正在尝试优化我的应用程序,以尽量减少垃圾收集的对象数量。

优化示例:我创建new Instrument(ticker)

,而不是多次调用HashSet<string /*ticker*/, Instrument>

因此有这样的统计数据会很有趣:当应用程序完成时,我想知道在执行期间有多少对象被垃圾收集。所以后者我可以将这个数字与“优化”版本进行比较,以检查“优化”是否真的有效。

如果无法获得此类统计信息,那么如何测试我的优化是否有效,即实际减少GC的使用?

2 个答案:

答案 0 :(得分:3)

在.NET中,您无需优化收集的对象数。收集的对象花费零收集时间(只要它们不需要最终确定,大多数不需要)。

您真正应该优化的是 live 对象的数量。 GC时间与您拥有的那些的数量成正比。您可以使用各种内存分析工具查看您拥有的内容,包括免费的CLR Profiler

原因在于,在GC中,GC通过浏览所有活动对象并通过移动它们来简单地“压缩”它们,使它们彼此相邻。死对象永远不会以任何方式进入。他们只是被忽略了。他们最终会被新的分配覆盖。

.NET的真正成本是每秒分配数万个对象,并且它们彼此之间以及与现有的活动对象之间存在深度互联。例如,您经常添加和删除节点的树。

答案 1 :(得分:1)

如何计算处置的对象取决于您的实施,但您可以获得GC Notifications

垃圾收集通知

这引入了.NET 3.5 SP1中的GC,以便在GC集合即将开始并且GC集合成功完成时生成通知。因此,如果您处于应用程序的资源密集型阶段,GC通知将允许您收到GC正在接近的通知,以便您可以停止当前进程并等待GC完成。这使您的应用程序可以顺利运行。

获取GC通知的步骤:

  • 呼叫GC.RegisterForFullGCNotification以允许在GC接近时发出通知。
  • 从应用程序创建一个新线程,并在方法GC.WaitForFullGCApproach和/或GC.WaitForFullGCComplete方法的无限循环中连续开始轮询。
  • 当必须引发通知时,该方法都返回GCNotificationStatus.Succeeded
  • 在调用线程时,使用GC.CancelFullGCNotification取消注册通知过程。

示例代码实现

public class MainProgram
{
    public static List<char[]> lst = new List<char[]>();
    public static void Main(string[] args)
    {
        try
        {
            // Register for a notification. 
            GC.RegisterForFullGCNotification(10, 10);

            // Start a thread using WaitForFullGCProc.
            Thread startpolling = new Thread(() =>
            {
                while (true)
                {
                    // Check for a notification of an approaching collection.
                    GCNotificationStatus s = GC.WaitForFullGCApproach(1000);
                    if (s == GCNotificationStatus.Succeeded)
                    {
                        //Call event

                        Console.WriteLine("GC is about to begin");
                        GC.Collect();

                    }
                    else if (s == GCNotificationStatus.Canceled)
                    {
                        // Cancelled the Registration
                    }
                    else if (s == GCNotificationStatus.Timeout)
                    {
                        // Timeout occurred.
                    }

                    // Check for a notification of a completed collection.
                    s = GC.WaitForFullGCComplete(1000);
                    if (s == GCNotificationStatus.Succeeded)
                    {
                        //Call event
                        Console.WriteLine("GC has ended");
                    }
                    else if (s == GCNotificationStatus.Canceled)
                    {
                        //Cancelled the registration
                    }
                    else if (s == GCNotificationStatus.Timeout)
                    {
                        // Timeout occurred
                    }

                    Thread.Sleep(500);
                }


            });
            startpolling.Start();

            //Allocate huge memory to apply pressure on GC
            AllocateMemory();

            // Unregister the process
            GC.CancelFullGCNotification();

        }
        catch { }
    }

    private static void AllocateMemory()
    {
        while (true)
        {

            char[] bbb = new char[1000]; // creates a block of 1000 characters
            lst.Add(bbb);                // Adding to list ensures that the object doesnt gets out of scope   
            int counter = GC.CollectionCount(2);
            Console.WriteLine("GC Collected {0} objects", counter);

        }
    }

}

参考:Garbage Collection Notifications in .NET 4.0