2017-08-03 84 views
0

我有一个在IIS中托管的asp.net网站。我最近注意到,从数据库返回大量结果集时,IIS工作进程的内存只是保持增长(每次查询运行时大约为400MB)。如果这些大型查询中的一些发生在同一时间运行,它可能会消耗内存(已经看到它达到了5GB),并且服务器放慢了速度。使用DataTable的ASP.NET内存泄漏/高内存

当数据加载到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中查询的结果,但我不确定该从哪里去?我误解我应该如何处理这个?

+1

https:// stackoverflow.com。com/questions/913228/should-i-dispose-dataset-and-datatable/1603516#1603516 – user6144226

+0

只有一个查询后400 MB内存?您是否考虑尽量减少从DB获取的数据集? – Piotr

+0

Piotr,不幸的是它不是立即可能的,它是一个有点遗留下来的系统,其中有大量的报告都是以相同的方式设计的。 – IanSoc

回答

0

这不是问题。这就是垃圾收集器的工作原理。 处理对象时,它不会立即从内存中删除。它只是被标记为准备好处理垃圾收集器。

这是从MS考试书报价

所述堆在方法结束时自动清除。 CLR照顾这一点,你不必担心它。堆是另一个故事 - 它由垃圾收集器管理。在没有垃圾收集器的非托管环境中,您必须跟踪堆中分配了哪些对象,并且需要明确释放它们。在.NET Framework中,这由垃圾收集器完成。

垃圾收集器使用标记和紧凑算法。集合的标记阶段检查堆上的哪些项目仍被根项目引用。根可以是静态字段,方法参数,局部变量或CPU寄存器。如果垃圾收集器在堆上找到“活的”项目,它将标记该项目。在检查整个堆之后,紧凑操作开始。垃圾收集器然后将所有活堆对象放在一起并释放所有其他对象的内存。为此,垃圾收集器必须确保在执行所有标记和压缩时没有状态变化。因此,所有线程在执行收集操作时都会被冻结。它还必须确保所有对活体的引用都是正确的。移动对象后,垃圾收集器将修复对象的所有现有引用。

你可以尝试强制垃圾回收利用来进行清洁:

GC.Collect(); 
GC.WaitForPendingFinalizers(); 

此外,GC采用多代,只有第0代易清理和GC先清理。只有当GC决定不能释放足够的内存时,它才会开始处理其他代。转向这些世代可能会造成延迟。

更新:您也可以尝试将您的大数据集分成小块并相应地检索它们。

+0

嗨信欣,谢谢你的回答。虽然直接调用垃圾回收器会清除内存,但我仍然不确定为什么它不会自动收集。我是不是在担心什么,事实上它会在需要时收集起来?我担心这一点的原因是因为这发生在多用户系统中,该用户系统也有多个报告,我看到分配给IIS的内存达到了5GB。我不应该为此担心吗? – IanSoc

+0

如果GC决定您的数据表位于第1代或第2代,那么您最好尝试更改逻辑。如果它在第0代。不要担心。你可以做什么,尽管只是覆盖数据表的Dispose方法,所以你可以确定它会自动清理。顺便说一句,它会自动收集它,但经过一段时间。 – SouXin