繁体   English   中英

如何释放由C#中的列表分配的内存

[英]How to free memory which is allocated by a List in C#

我有这样的代码:

var myList = db.Table1.ToList();
/*doing some operations on the list*/
var myList = db.Table2.ToList();
/*again doing some operations on the list*/
var myList = db.Table3.ToList(); // I'm getting out of memory exception here.

我无法按页面检索数据,因为我只需要一次使用所有表。 在加载另一个表之前,我该如何处置(我的意思是释放该列表分配的空间)列表? 谢谢。

编辑:

加载后,实际上是从myList生成许多(有时数千个)子列表。 因此,我真的需要学习如何释放列表。

编辑2:这是我完整的Stacktrace:

   at System.Collections.Generic.List`1.set_Capacity(Int32 value)
   at System.Collections.Generic.List`1.EnsureCapacity(Int32 min)
   at System.Collections.Generic.List`1.Add(T item)
   at System.Data.Entity.Core.Objects.EntityEntry.TakeSnapshot(Boolean onlySnapshotComplexProperties)
   at System.Data.Entity.Core.Objects.Internal.SnapshotChangeTrackingStrategy.TakeSnapshot(EntityEntry entry)
   at System.Data.Entity.Core.Objects.Internal.EntityWrapper`1.TakeSnapshot(EntityEntry entry)
   at System.Data.Entity.Core.Objects.ObjectStateManager.AddEntry(IEntityWrapper wrappedObject, EntityKey passedKey, EntitySet entitySet, String argumentName, Boolean isAdded)
   at System.Data.Entity.Core.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly[TEntity](Func`2 constructEntityDelegate, EntityKey entityKey, EntitySet entitySet)
   at System.Data.Entity.Core.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper)
   at System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext()
   at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
   at System.Collections.Generic.List`1.InsertRange(Int32 index, IEnumerable`1 collection)
   at System.Collections.Generic.List`1.AddRange(IEnumerable`1 collection)
   at WebApplication2.MyMethod in line 2292
   at WebApplication2.Controllers.MyController.MyActtion(String myString) in line 137
   at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
   at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()

根据评论中的其他说明, db是EF DbContext派生的类变量,在3个调用之间共享 Table1Table2Table3DbSet这方面的内部情况。

当使用var myList = db.Table1.ToList() ,除了读取内存中的表并填充列表外,EF DbContext还使用相同的对象填充内部DbSet.Local集合(即所谓的tracking )。为了能够检测并最终将您所做的更改应用于基础对象。

这就是问题所在。 如果将Clear设置为myList变量为null ,则内部缓存(列表)仍将保留所有这些对象,最终在某个时候导致OutOfMemoryException

因此,窍门是,如果您不打算修改返回的对象并将其保存回数据库,则可以使用所谓的“ 无跟踪查询”来完全消除DbContext内部缓存。

var myList = db.Table1.AsNoTracking().ToList();

或清理( Dispose并设置为null )并为每个列表进程使用新的新上下文( db = new YourDbContext() )。

当然,您可以将以上内容与注释中提到的其他技术结合使用,以清理自己的列表变量。

根据我上面的评论,当处理大量项目时, ToList可能在内存上非常混乱。

因此,有时可以通过预分配列表来获得更好的内存性能。

所以:

var tableCount = db.Table1.Count();
var myList = new List<Table1Item>(tableCount); //I don't know the type parameter here
myList.AddRange(db.Table1); //or db.Table1.AsEnumerable() ?

暂无
暂无

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

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