代码之家  ›  专栏  ›  技术社区  ›  TJF

.NET预分配内存与特殊分配

  •  3
  • TJF  · 技术社区  · 15 年前

    我原以为预先分配内存的测试运行会执行得更快,但令我惊讶的是,它们实际上稍微慢了一点(当我让测试运行10分钟时,平均差异约为400毫秒)。

    下面是我使用的测试代码:

        class Program
    {
        private static byte[] buffer = new byte[50];
        private static List<byte[]> preAlloctedList = new List<byte[]>(500);
    
        static void Main(string[] args)
        {
            for (int k = 0; k < 5; k++)
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
    
                for (int i = 0; i < 1000000; i++)
                {
                    List<byte[]> list = new List<byte[]>(300);
    
                    for (int j = 0; j < 300; j++)
                    {
                        list.Add(buffer);
                    }
                }
    
                sw.Stop();
                Console.WriteLine("#1: " + sw.Elapsed);
                sw.Reset();
                sw.Start();
    
                for (int i = 0; i < 1000000; i++)
                {
                    for (int j = 0; j < 300; j++)
                    {
                        preAlloctedList.Add(buffer);
                    }
    
                    preAlloctedList.Clear();
                }
                sw.Stop();
                Console.WriteLine("#2: " + sw.Elapsed);
            }
    
            Console.ReadLine();
        }
    }
    

    现在,真正有趣的是,我在并排运行perfmon时看到了以下模式,看起来像我预期的那样:

    绿色=0代系列
    蓝色=分配字节/秒
    红色=GC中的时间


    alt text

    所以,我的问题是,为什么测试1比测试2快?
    显然,我更希望在我的应用程序中使用测试2的perfmon统计信息,因为基本上没有内存压力,没有GC集合等,但是1似乎要快一点?
    List.Clear()的开销有这么大吗?

    谢谢,

    汤姆

    编辑 我做了另一个测试,使用相同的设置,但是在启用服务器GC的情况下运行应用程序,现在#2变得稍微快了一点 alt text

    2 回复  |  直到 15 年前
        1
  •  4
  •   Reed Copsey    15 年前

    我怀疑Test#1更快的原因是垃圾收集是在一个单独的线程上进行的,并且分配的开销低于额外的 List<T>.Clear 打电话来。因为这些列表都不是大的(每个只有300个引用),而且它们都是在一个紧密的循环中创建和取消的,所以它们通常都会留在Gen 0中。

    在过去的评测中我注意到了这一点-重用 List<T> 而且,明确的要求往往比重新分配要慢。 Clear() 实际上,清除内部数组并重置列表的参数,我相信这比列表的初始分配有(稍微)更多的开销。

    然而,在我看来,这个例子确实表明.NET中的GC非常非常有效。

        2
  •  3
  •   Henk Holterman    15 年前

    List.Clear()的开销有这么大吗?

    GC.Collect(0) ,打几千个电话给 Clear() 可能会慢一点。

    但是要小心把这个简单测试的结论带到你真正的应用上。