并发垃圾回收的.Net 4 MemoryCache泄漏

|| 我正在.Net 4中使用新的MemoryCache,最大缓存大小限制为MB(我已经测试了它的设置在10到200MB之间,在内存为1.75到8GB之间的系统上)。我没有在对象上设置任何基于时间的到期,因为我只是将缓存用作高性能驱动器,并且只要有空间,我都希望使用它。令我惊讶的是,缓存拒绝逐出任何对象,以至于我将得到“ 0”异常。 我启动了perfmon,将我的应用程序连接到
.Net CLR Memory\\#Bytes In All Heaps
.Net Memory Cache 4.0
和ѭ3indeed -确实,内存消耗已失控,并且未注册任何缓存修剪。 做了一些谷歌搜索和stackoverflowing,下载并附加了CLRProfiler,并且感到震惊:无处不在!根据我设置的内存大小限制,内存处于合理范围内。再次以调试模式运行它,没有逐出。 CLRProfiler再次驱逐。 我终于注意到,探查器强制应用程序在不进行并发垃圾收集的情况下运行(另请参见有用的SO并发垃圾收集问题)。我在我的app.config中将其关闭,而且,确实有逐出! 这似乎充其量是因为缺少文档,这简直是令人发指的缺乏:这仅适用于非并发垃圾收集-尽管我自从ASP.NET移植以来就对其进行了映像,但他们可能不必担心并发垃圾收集。 那么还有其他人看到吗?我想从那里获得其他一些经验,也许还有一些受过教育的见解。 更新1 我在一个方法中重现了该问题:似乎必须并行写入缓存,以使缓存逐出不触发(在并发垃圾收集模式下)。如果有兴趣,我会将测试代码上传到公共存储库中。我肯定会进入CLR / GC / MemoryCache池的最深处,我想我忘记了浮动信息... 更新2 我在CodePlex上发布了测试代码以重现此问题。另外,可能感兴趣的是,原始生产代码作为工作角色在Azure中运行。有趣的是,更改角色的app.config中的GC并发设置无效。可能Azure会像ASP.NET一样覆盖GC设置吗?此外,在WPF和控制台应用程序下运行测试代码将产生稍微不同的驱逐结果。     
已邀请:
您可以在有问题的方法之后“强制”垃圾回收,然后查看问题是否再现为执行:
System.Threading.Thread.Sleep(200);
GC.Collect();
GC.WaitForPendingFinalizers();
就在方法末尾(确保释放所有句柄以引用对象并将它们归零)。如果这防止内存泄漏,然后是,则可能存在运行时错误。     
停止世界垃圾回收基于确定世界停止时是否存在对对象的强大实时引用。并发垃圾回收通常确定自过去某个特定时间以来是否已经存在对对象的强大实时引用。我的推测是,对WeakReferences中保存的对象的许多强大引用正在单独创建和丢弃。如果在创建特定对象与废弃该对象之间触发了世界各地的垃圾收集器,则该特定对象将保持活动状态,而先前丢弃的对象将不会保留。相比之下,并发垃圾回收器可能会检测到某个对象的所有强引用都已被丢弃,直到经过一定的时间而没有创建对该对象的任何强引用。 有时我希望.net在强引用和弱引用之间提供某种东西,以防止从内存中擦除对象,但不能保护它免于终结或弱化使它无效的WeakReferences。这样的引用会使GC过程稍微复杂化,要求每个对象都具有单独的标志,指示是否存在强引用和准弱引用,以及是否已对其进行扫描以查找强引用和准弱引用,但是此功能可能会有所帮助在许多“弱事件”场景中。     
我在搜索类似主题时找到了此条目,我正在关注您的“内存不足”异常。 如果将对象放入高速缓存中,则该对象可能仍在引用其他对象,因此不会对这些对象进行垃圾回收-因此,内存不足异常可能是由于Gen 2垃圾回收而将CPU钉住了。 您是将“已用”对象放在缓存上还是将“已用”对象的克隆放在缓存上?如果将克隆放在缓存中,则可能会引用其他对象的“已使用”对象可能会被垃圾回收。 如果关闭了缓存机制,程序是否仍会耗尽内存?如果它没有用完内存,那将证明您原本放在缓存中的对象仍然持有对其他对象的引用,从而阻碍了垃圾回收。 强制垃圾回收不是最佳实践,也不必这样做。在这种情况下,强制垃圾回收将不会处理引用的对象。     
MemoryCache肯定有一些问题。它在我的asp.net服务器上吃了160Mb的内存,只是更改为简单列表,并添加了一些额外的逻辑来获得相同的功能。     

要回复问题请先登录注册