.NET 预分配内存与临时分配

标签 .net memory garbage-collection

我正在开发一些需要非常低延迟并占用大量内存的应用程序,并且正在做一些测试,例如如何临时分配列表与预分配和清除列表的执行情况不同。 我原以为预分配内存的测试运行会执行得更快,但令我惊讶的是,它们实际上稍微慢一些(当我让测试运行 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 时间

下面的控制台应用程序显示了 #1 和 #2 的测试运行时
alt text

所以,我的问题是,为什么测试 #1 比测试 #2 快?
显然,我宁愿在我的应用程序中拥有测试 #2 的性能统计数据,因为基本上没有内存压力,没有 GC 收集等。但 #1 似乎稍微快一些?
List.Clear() 会带来那么多开销吗?

谢谢

汤姆

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

最佳答案

我怀疑测试 #1 更快的原因是垃圾收集发生在单独的线程上,并且分配的开销低于额外的 List<T>.Clear称呼。由于这些列表都不是很大(每个列表只有 300 个引用),并且它们都是在紧密循环中创建和取消的,因此它们通常都保留在 Gen 0 中。

我在过去的分析过程中注意到了这一点 - 重用 List<T>对其调用 Clear 通常比重新分配要慢。 Clear()实际上清除了内部数组并重置了列表的参数,我相信这比列表的初始分配有(稍微)更多的开销。

但是,在我看来,这个示例实际上只是表明 .NET 中的 GC 非常非常高效。

关于.NET 预分配内存与临时分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3981437/

相关文章:

java - Microsoft 和 Oracle/Sun 技术之间是否存在等效性?

.net - 如何找出导致通用 'Application cannot be started. Contact the application vendor.' ClickOnce 错误的原因?

c# - System.Exception 是否有内置的抛出时间戳?

asp.net - 尝试使用未为此报表服务器注册或不受此版本支持的数据扩展

c++ - C++ "reference"是如何引用一个变量的?

c++ - unique_ptr 矩阵

c++ - 将共享指针还是原始指针传递给函数

java - 如何计算对象对 Java 中垃圾收集器的资格?

java - 错误 java.lang.OutOfMemoryError : GC overhead limit exceeded

reference - 引用循环的实际例子有哪些?