我有一个在IIS中托管的asp.net网站。我最近注意到,从数据库返回大型结果集,IIS Worker Process的内存不断增长(每次运行查询时大约400MB)。如果这些大型查询中的一些碰巧同时运行,它可能只会占用内存(已经看到它达到5GB)并且服务器会慢下来。
当数据加载到DataTable中时,我已将其缩小为一行代码。
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(storedProcedureName, connection))
using(DataTable dataTable = new DataTable())
{
command.CommandType = System.Data.CommandType.StoredProcedure;
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
// Memory Spikes on dataTable.Load
dataTable.Load(reader);
}
}
我不明白的是,分配给DataTable的内存似乎并没有像我预期的那样被处理掉。当DataTable超出范围或者导航网页时,甚至当用户退出站点时,内存保持在同一级别。这显然是多用户系统中的一个问题。
我使用了一个内存分析器,它在内存中保存了数千个字符串,这些字符串是DataTable中保存的查询结果,但我不确定从哪里开始?我误解了我应该如何处理这个问题?
答案 0 :(得分:0)
这不是问题。垃圾收集器的工作原理。 处理对象时,不会立即将其从内存中删除。它只是标记为垃圾收集器的处理。
这是MS Exams一书的引用
在方法结束时自动清除堆栈。 CLR负责这一点,你不必担心它。堆是另一个故事 - 它由垃圾收集器管理。在没有垃圾收集器的非托管环境中,您必须跟踪堆上分配的对象,并且需要显式释放它们。在.NET Framework中,这是由垃圾收集器完成的。
垃圾收集器使用标记和紧凑算法。集合的标记阶段检查堆上的哪些项目仍由根项目引用。根可以是静态字段,方法参数,本地变量或CPU寄存器。如果垃圾收集器在堆上找到“活”项,则标记该项。检查整个堆后,紧凑操作开始。然后,垃圾收集器将所有活动堆对象移近,并释放所有其他对象的内存。为此,垃圾收集器必须确保在执行所有标记和压缩时没有状态发生变化。因此,在执行收集操作时会冻结所有线程。它还必须确保对生物对象的所有引用都是正确的。移动对象后,垃圾收集器将修复对象的所有现有引用。
您可以尝试使用以下方法强制垃圾收集器执行清理:
GC.Collect();
GC.WaitForPendingFinalizers();
此外,GC使用多代,只有第0代易于清理,GC首先清理它。只有GC才决定它不能释放足够的内存,它将开始处理其他几代。转向这些世代可能会产生延迟。
更新:您还可以尝试将大数据集划分为小块并相应地检索它们。