我有一个asp.net网站是托管在IIS中的。我最近注意到,随着从数据库返回大量结果集,IIS工作进程的内存不断增加(每次运行查询时大约为400 is )。如果这些大型查询中有几个同时运行,它就会占用内存(已经看到内存达到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中保存的查询的结果,但我不知道从哪里开始呢?我是不是误解了我该怎么处理这件事?
发布于 2017-08-03 08:50:34
这不是问题所在。垃圾收集器就是这样工作的。当您释放一个对象时,它不会立即从内存中删除。它只是被标记为准备用于垃圾收集器。
这是微软考试书的引文。
堆栈在方法结束时自动清除。CLR会处理这件事,你不必担心。堆是另一个故事-它由垃圾收集器管理。在没有垃圾收集器的非托管环境中,您必须跟踪堆上分配了哪些对象,并且需要显式地释放它们。在.NET框架中,这是由垃圾收集器完成的。 垃圾收集器使用标记和紧凑算法工作。集合的标记阶段检查堆上的哪些项仍由根项引用。根可以是静态字段、方法参数、局部变量或CPU寄存器。如果垃圾收集器在堆中找到一个“活动”项,它将标记该项。检查完整个堆后,紧凑型操作将启动。然后,垃圾收集器将所有活动堆对象紧密地移动在一起,并释放所有其他对象的内存。要做到这一点,垃圾收集器必须确保在执行所有标记和压缩时没有状态发生更改。因此,所有线程在执行收集操作时都会被冻结。它还必须确保所有对活动对象的引用都是正确的。在移动对象之后,垃圾收集器将修复对对象的所有现有引用。
您可以尝试使用以下方法强制垃圾收集器执行清理:
GC.Collect();
GC.WaitForPendingFinalizers();
此外,GC使用多代,只有第0代才容易清理,而GC首先要清理它。只有这样,GC才决定不能释放足够的内存--它将开始处理其他代的内存。而转移到这几代人可能会造成延迟。
更新:您也可以尝试将大数据集划分为小块并相应地检索它们。
https://stackoverflow.com/questions/45490237
复制