简体   繁体   English

使用DataTable的ASP.NET内存泄漏/高内存

[英]ASP.NET Memory Leak/High Memory using DataTable

I have an asp.net website that is being hosted in IIS. 我有一个由IIS托管的asp.net网站。 I have recently noticed that with large result sets being returned from the database, that the memory for IIS Worker Process just keeps growing (about 400MB each time the query is run). 我最近注意到,随着从数据库返回大量结果集,IIS Worker Process的内存一直在增长(每次运行查询大约400MB)。 If a few of these large queries happen to be run at the same time it can just eat away at the memory (have seen it reach 5GB) and the server slows right down. 如果其中一些大型查询恰巧同时运行,则它可能会消耗掉内存(已经达到5GB),并且服务器会立即变慢。

I have narrowed it down to a single line of code, when the data is loaded into the DataTable. 当数据加载到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);
    }
}

What I dont understand is that the memory being allocated to the DataTable doesn't seem to be disposed of as I would expect. 我不明白的是,分配给DataTable的内存似乎没有像我期望的那样被处置。 When the DataTable falls out of scope or when the webpage is navigated away from or even when the user logs out of the site, the memory stays at the same level. 当DataTable超出范围时,或者在导航页面离开或什至当用户注销站点时,内存将保持在同一级别。 This is obviously an issue in a multi user system. 在多用户系统中,这显然是一个问题。

I have used a memory profiler and it is holding thousands of strings in memory which are the results of the query held in the DataTable, but I am not really sure where to go from here? 我使用了一个内存探查器,它在内存中保存了成千上万个字符串,这些字符串是保存在DataTable中的查询结果,但是我真的不确定从哪里走吗? Am I misunderstanding how I should be handling this? 我是否误解了应该如何处理?

It's not the issue. 这不是问题。 It's how Garbage Collector works. 这就是垃圾收集器的工作方式。 When you dispose of an object it is not removed from memory right away. 处理对象时,不会立即将其从内存中删除。 It's just marked as ready to be disposed of for garbage collector. 它只是标记为准备好用于垃圾收集器处理。

This is a quote from MS Exams book 这是MS考试书的引言

The stack is automatically cleared at the end of a method. 方法结束时将自动清除堆栈。 The CLR takes care of this and you don't have to worry about it. CLR会处理此问题,您不必担心。 The heap is another story—it is managed by the garbage collector. 堆是另一回事-它由垃圾收集器管理。 In unmanaged environments without a garbage collector, you have to keep track of which objects were allocated on the heap and you need to free them explicitly. 在没有垃圾收集器的非托管环境中,您必须跟踪在堆上分配了哪些对象,并且需要显式释放它们。 In the .NET Framework, this is done by the garbage collector. 在.NET Framework中,这是由垃圾收集器完成的。

The garbage collector works with a mark and compact algorithm. 垃圾收集器使用标记和紧凑算法。 The mark phase of a collection checks which items on the heap are still being referenced by a root item. 集合的标记阶段检查根项仍在引用堆中的哪些项。 A root can be a static field, a method parameter, a local variable, or a CPU register. 根可以是静态字段,方法参数,局部变量或CPU寄存器。 If the garbage collector finds a “living” item on the heap, it marks the item. 如果垃圾收集器在堆上找到“活动的”项目,则会对其进行标记。 After checking the whole heap, the compact operation starts. 在检查了整个堆之后,压缩操作开始。 The garbage collector then moves all living heap objects close together and frees the memory for all other objects. 然后,垃圾收集器将所有活动的堆对象移到一起,并为所有其他对象释放内存。 For doing this, the garbage collector has to make sure that no state is changing while performing all the marking and compacting. 为此,垃圾收集器必须确保在执行所有标记和压缩时没有任何状态发生变化。 Because of this, all threads are frozen while doing a collect operation. 因此,所有线程在执行收集操作时都被冻结。 It also has to make sure that all references to living objects are correct. 还必须确保所有对活动物体的引用都是正确的。 After moving objects around, the garbage collector will fix all existing references to objects. 在移动对象之后,垃圾收集器将修复所有对对象的现有引用。

You can try to force garbage collector to perform cleaning using: 您可以尝试使用以下方法强制垃圾收集器执行清理:

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

Moreover, GC uses multiple generations and only Generation 0 is easy to clean-up and GC clean it up first. 此外,GC使用了多个世代,只有第0世代很容易清理,而GC首先会清理它。 Only then GC decided that it cannot release enough memory it will start to process the other generations. 只有到那时GC才决定不能释放足够的内存,它将开始处理其他世代。 And moving to these generations could create latency. 而转移到这些世代可能会造成延迟。

UPDATE: You can try also divide your big dataset to small chunks and retrieve them accordingly. 更新:您也可以尝试将大数据集分成小块,并相应地进行检索。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM