列表性能与 ArrayList 内存分配性能
List perfomance vs ArrayList memory allocation performance
我有以下代码:
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;然后 List 以 2:6 毫秒的比例优于 ArrayList。但是如果让 size = 70000000;然后 ArrayList 在我的电脑上有更好的性能 5450:4809。看起来处理巨大的(大约数百万个项目)ArrayList 可能比 List 更快。为什么 boxing/unboxing 对小内存分配很重要,而对大数组无关紧要
你的误会比这还深一点。
首先,制定一个好的基准很难 - 你的不好。
其次,仅在 值类型 上进行装箱 - 您在这两种情况下都添加了 class,因此即使 ArrayList
也不会发生装箱。事实上,通过将 double
包装在 class 中,您只是手动 装箱 值 - 这就是装箱的意思(当然,IL box
/ unbox
指令可能更有效)。尝试直接插入 double
,您会发现巨大的差异。
为了进一步说明基准测试问题,您完全忽略了内存分配(和收集)模式。当您自己预分配数组时(这就是容量参数的用途),您并没有预分配对象 (Foo
)。例如,这对于结构或 double
s 并不重要,但在这种情况下,您只是将所有内存压力推入相关周期。
List
只要不再在方法中使用就可以收集,因此 ArrayList
将在需要收集时立即获得空闲的预先准备好的内存。所以即使是测试的顺序也会有很小的不同。
最后,您需要可重复性 - 使用 List
进行一百次测试,使用 ArrayList
进行另外一百次测试,尽可能多地进行隔离。并且不要忘记预热基准测试以消除初始化时间。
您可以找到很多关于在 C# 中制作像样的基准测试的信息。真的不容易。
我有以下代码:
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;然后 List 以 2:6 毫秒的比例优于 ArrayList。但是如果让 size = 70000000;然后 ArrayList 在我的电脑上有更好的性能 5450:4809。看起来处理巨大的(大约数百万个项目)ArrayList 可能比 List 更快。为什么 boxing/unboxing 对小内存分配很重要,而对大数组无关紧要
你的误会比这还深一点。
首先,制定一个好的基准很难 - 你的不好。
其次,仅在 值类型 上进行装箱 - 您在这两种情况下都添加了 class,因此即使 ArrayList
也不会发生装箱。事实上,通过将 double
包装在 class 中,您只是手动 装箱 值 - 这就是装箱的意思(当然,IL box
/ unbox
指令可能更有效)。尝试直接插入 double
,您会发现巨大的差异。
为了进一步说明基准测试问题,您完全忽略了内存分配(和收集)模式。当您自己预分配数组时(这就是容量参数的用途),您并没有预分配对象 (Foo
)。例如,这对于结构或 double
s 并不重要,但在这种情况下,您只是将所有内存压力推入相关周期。
List
只要不再在方法中使用就可以收集,因此 ArrayList
将在需要收集时立即获得空闲的预先准备好的内存。所以即使是测试的顺序也会有很小的不同。
最后,您需要可重复性 - 使用 List
进行一百次测试,使用 ArrayList
进行另外一百次测试,尽可能多地进行隔离。并且不要忘记预热基准测试以消除初始化时间。
您可以找到很多关于在 C# 中制作像样的基准测试的信息。真的不容易。