列出性能与ArrayList内存分配性能

时间:2015-02-05 12:36:33

标签: c# .net list arraylist

我有以下代码:

namespace ConsoleCodeGenerator
{
    internal class Foo
    {
        public double F { get; set; }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            //int size = 100000;
            int size = 70000000;

            List<Foo> list = new List<Foo>(size);
            ArrayList arrayList = new ArrayList(size);

            Stopwatch sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < size; i++)
            {
                Foo f = new Foo();
                f.F = i;
                list.Add(f);
            }
            sw.Stop();
            Console.WriteLine("List: {0}", sw.ElapsedMilliseconds);

            Stopwatch sw2 = new Stopwatch();
            sw2.Start();
            for (int i = 0; i < size; i++)
            {
                Foo f = new Foo();
                f.F = i;
                arrayList.Add(f);
            }
            sw2.Stop();
            Console.WriteLine("arrayList: {0}", sw2.ElapsedMilliseconds);
        }
    }
}

如果我使用int size = 100000;然后按比例2:6​​毫秒列出outperfoms ArrayList。但是如果要制作尺寸= 70000000;然后ArrayList在我的电脑上有更好的性能5450:4809。它看起来像处理巨大(大约数百万项)ArrayList可能比List更快。为什么装箱/拆箱在小内存分配时很重要,而在大阵列无关紧要

1 个答案:

答案 0 :(得分:4)

你的误解比这更深刻。

首先,制定一个好的基准很难 - 你的不好。

其次,装箱仅发生在值类型上 - 您在两种情况下都添加了一个类,因此即使使用ArrayList也不会发生装箱。事实上,通过将double包装在一个类中,您只需手动装箱该值 - 这就是拳击意味着什么(当然,IL {{1 } / box指令可能更有效率)。尝试直接插入unbox,您就会看到巨大的差异。

为了扩展基准测试问题,您完全忽略了内存分配(和集合)模式。虽然您自己预先分配了数组(这是容量参数的用途),但您并未预先分配对象(double)。例如,对于结构或Foo s,这不重要,但在这种情况下,您只需将所有内存压力推入相关周期。

double一旦在方法中不再使用,就可以收集List,因此ArrayList只要需要,就会获得免费的,预先准备好的内存采集。因此,即使是测试的顺序也会产生很小的差异。

最后,您需要重复性 - 使用List进行一百次测试,使用ArrayList进行一百次测试,并尽可能地隔离。并且不要忘记预热基准以摆脱初始化时间。

您可以在C#中找到有关制作体面基准的大量信息。这真的不容易。