我一直认为DataTable会消耗比通用List更多的内存。我正在测试加载DataTable并从SQL Server查询加载List。在这种情况下,DataTable消耗的内存较少。我得到了前2000行,每行有134个字段。一个二进制字段,其余为标准varchar,int,bit等。
如果DataTable的所有开销都比List更少,那么它在世界上会有多少? GC使用DataTable报告大约4mb,使用列表报告5mb。
我用一些NorthWind表进行了测试,在这些情况下,列表略小一些。
private void GetMemory()
{
label1.Text = string.Format("{0:0.00} MB", GC.GetTotalMemory(true) / 1024.0 / 1024.0);
}
private void DataTableButton_Click(object sender, EventArgs e)
{
var conn = new SqlConnection(@"Initial Catalog=ADatabase;Data Source=AServer;Integrated Security=True");
conn.Open();
var cmd = new SqlCommand("SELECT TOP 2000 * FROM AManyColumnedTable", conn);
var r = cmd.ExecuteReader();
_rows = new List<object[]>();
//uses more memory
object[] a = null;
while (r.Read())
{
a = new object[r.FieldCount];
r.GetValues(a);
_rows.Add(a);
}
//uses less memory
//_table = new DataTable("TheTable");
//_table.Load(r);
r.Close();
conn.Close();
GetMemory();
}
答案 0 :(得分:4)
这是一种幻觉。不知何故GC没有给你正确的值,也许是因为有些对象尚未收集。也许加载数据表会导致更多的中间对象,从而导致另一次垃圾收集。
您的数组列表以与数据表相同的方式存储数据,但没有数据表和每个数据行包含的额外信息的开销。
如果希望它的内存效率更高,则应为数据记录创建一个类,这样您就可以将值类型存储为普通值而不是在对象中装箱。例如,一个int在装箱时使用20个字节,但只有4个作为普通成员变量。
答案 1 :(得分:1)
出于好奇,尝试在List上调用TrimExcess,然后检查内存。我怀疑这会产生很大的不同,但我怀疑它会有所不同。
基本上,List会分批增长。每次添加对象时它都不会增长,而是增加一定量,然后如果它需要更多,它会分配更多。我很好奇你的列表中是否有一些你没有使用的额外空间。
答案 2 :(得分:0)
对我来说,它恰好相反。好吧,我没有从数据库中获取数据,而是使用批量插入将数据推送到数据库。在处理数据时,我获得了大约5000万条记录作为输出,我想将其存储到数据库中。我使用DataTable(只有8列)使用每次推送200k行的批量插入,并发现每次插入时平均需要大约95 MB的数据(使用网络监视工具和序列化器来查找对象的大小)。当我使用List(使用IDataReader)进行批量插入时,它将(一次推送)推送的大小降低到15 MB平均值(使用序列化来查找对象的大小并在任务管理器中监视)。使用DataTable处理和上传数据所需的时间为1657秒,使用List方法将其降至850秒。