我有一个动态查询,返回大约590,000条记录.它第一次成功运行,但是如果我再次运行它,我会继续运行System.OutOfMemoryException
.这可能发生的原因是什么?
错误发生在这里:
public static DataSet GetDataSet(string databaseName,string storedProcedureName,params object[] parameters) { //Creates blank dataset DataSet ds = null; try { //Creates database Database db = DatabaseFactory.CreateDatabase(databaseName); //Creates command to execute DbCommand dbCommand = db.GetStoredProcCommand(storedProcedureName); dbCommand.CommandTimeout = COMMAND_TIMEOUT; //Returns the list of SQL parameters associated with that stored proecdure db.DiscoverParameters(dbCommand); int i = 1; //Loop through the list of parameters and set the values foreach (object parameter in parameters) { dbCommand.Parameters[i++].Value = parameter; } //Retrieve dataset and set to ds ds = db.ExecuteDataSet(dbCommand); } //Check for exceptions catch (SqlException sqle) { throw sqle; } catch (Exception e) { throw e; // Error is thrown here. } //Returns dataset return ds; }
以下是单击按钮时运行的代码:
protected void btnSearchSBIDatabase_Click(object sender, EventArgs e) { LicenseSearch ls = new LicenseSearch(); DataTable dtSearchResults = new DataTable(); dtSearchResults = ls.Search(); Session["dtSearchResults"] = dtSearchResults; Response.Redirect("~/FCCSearch/SearchResults.aspx"); } else lblResults.Visible = true; }
Juliet.. 43
它第一次成功运行,但如果我再次运行它,我会不断收到System.OutOfMemoryException.这可能发生的原因是什么?
无论其他人说了什么,该错误与忘记处理您的DBCommand或DBConnection无关,并且您不会通过处置其中任何一个来修复错误.
该错误与您的数据集有关,该数据集包含近600,000行数据.显然,您的数据集占用了计算机可用内存的50%以上.显然,当您在第一个数据集被垃圾回收之前返回相同大小的另一个数据集时,您将耗尽内存.就那么简单.
您可以通过以下几种方式解决此问题:
考虑返回更少的记录.我个人无法想象返回600K记录对用户有用的时间.要最小化返回的记录,请尝试:
将查询限制为前1000条记录.如果查询返回的结果超过1000个,请通知用户缩小搜索结果范围.
如果您的用户真的坚持一次看到那么多数据,请尝试分页数据.请记住:谷歌从未向您展示一次搜索的全部22个bajillion结果,它一次显示20条左右的记录.谷歌可能不会立即将所有22亿条结果保存在内存中,它可能会发现其更高的内存效率来重新查询其数据库以生成新页面.
如果您只需要遍历数据并且不需要随机访问,请尝试返回datareader.datareader一次只能将一条记录加载到内存中.
如果这些都不是一个选项,那么在使用以下方法之一调用方法之前,需要强制.NET释放数据集使用的内存:
删除对旧数据集的所有引用.任何坚持数据集参考的东西都会阻止它被内存回收.
如果无法清空对数据集的所有引用,请清除数据集中的所有行以及绑定到这些行的所有对象.这将删除对数据行的引用,并允许它们被垃圾收集器吃掉.
我不相信你需要打电话GC.Collect()
来强制进行循环.调用通常不是一个坏主意GC.Collect()
,因为足够的内存压力会导致.NET自己调用垃圾收集器.
注意:在数据集上调用Dispose不会释放任何内存,也不会调用垃圾收集器,也不会删除对数据集的引用.Dispose用于清理非托管资源,但DataSet没有任何非托管资源.它只实现了IDispoable,因为它来自MarshalByValueComponent,所以数据集上的Dispose方法几乎没用.
它第一次成功运行,但如果我再次运行它,我会不断收到System.OutOfMemoryException.这可能发生的原因是什么?
无论其他人说了什么,该错误与忘记处理您的DBCommand或DBConnection无关,并且您不会通过处置其中任何一个来修复错误.
该错误与您的数据集有关,该数据集包含近600,000行数据.显然,您的数据集占用了计算机可用内存的50%以上.显然,当您在第一个数据集被垃圾回收之前返回相同大小的另一个数据集时,您将耗尽内存.就那么简单.
您可以通过以下几种方式解决此问题:
考虑返回更少的记录.我个人无法想象返回600K记录对用户有用的时间.要最小化返回的记录,请尝试:
将查询限制为前1000条记录.如果查询返回的结果超过1000个,请通知用户缩小搜索结果范围.
如果您的用户真的坚持一次看到那么多数据,请尝试分页数据.请记住:谷歌从未向您展示一次搜索的全部22个bajillion结果,它一次显示20条左右的记录.谷歌可能不会立即将所有22亿条结果保存在内存中,它可能会发现其更高的内存效率来重新查询其数据库以生成新页面.
如果您只需要遍历数据并且不需要随机访问,请尝试返回datareader.datareader一次只能将一条记录加载到内存中.
如果这些都不是一个选项,那么在使用以下方法之一调用方法之前,需要强制.NET释放数据集使用的内存:
删除对旧数据集的所有引用.任何坚持数据集参考的东西都会阻止它被内存回收.
如果无法清空对数据集的所有引用,请清除数据集中的所有行以及绑定到这些行的所有对象.这将删除对数据行的引用,并允许它们被垃圾收集器吃掉.
我不相信你需要打电话GC.Collect()
来强制进行循环.调用通常不是一个坏主意GC.Collect()
,因为足够的内存压力会导致.NET自己调用垃圾收集器.
注意:在数据集上调用Dispose不会释放任何内存,也不会调用垃圾收集器,也不会删除对数据集的引用.Dispose用于清理非托管资源,但DataSet没有任何非托管资源.它只实现了IDispoable,因为它来自MarshalByValueComponent,所以数据集上的Dispose方法几乎没用.
也许你没有处理上一次运行中的先前连接/结果类,这意味着它们仍然在内存中闲置.