从静态对象中包含的C#字典中释放内存

从静态对象中包含的C#字典中释放内存,c#,memory-leaks,garbage-collection,memory-management,C#,Memory Leaks,Garbage Collection,Memory Management,我在使用WCFWeb服务时遇到了一些问题(一些转储、内存泄漏等),我运行了一个profillng工具(ANTS内存配置文件) 只是想知道,即使处理结束(我运行了一个特定的测试,然后停止了),第2代仍然占web服务内存的25%。我跟踪这个内存,发现我有一个dictionary对象,其中充满了(null,null)项,哈希代码为-1 web服务的工作流程意味着在特定的处理过程中,项目被添加,然后从字典中删除(只需简单的Add和Remove)。没什么大不了的。但似乎在删除所有项之后,字典中充满了(nu

我在使用WCFWeb服务时遇到了一些问题(一些转储、内存泄漏等),我运行了一个profillng工具(ANTS内存配置文件)

只是想知道,即使处理结束(我运行了一个特定的测试,然后停止了),第2代仍然占web服务内存的25%。我跟踪这个内存,发现我有一个dictionary对象,其中充满了(null,null)项,哈希代码为-1

web服务的工作流程意味着在特定的处理过程中,项目被添加,然后从字典中删除(只需简单的
Add
Remove
)。没什么大不了的。但似乎在删除所有项之后,字典中充满了(null,null)
KeyValuePair
s。事实上,它们有数千个,占用了很大一部分内存,最终发生了溢出,相应的强制应用程序池回收和DW20.exe获得了它所能获得的所有CPU周期

这本字典实际上是
字典
(),所以我已经检查过是否有某种引用包含东西

字典包含在一个静态对象中(通过处理使它可以访问不同的处理线程),因此从这个问题以及更多()中,我理解了为什么字典会出现在第2代中。但这也是这些(空,空)的原因吗?即使我从字典中删除了一些条目,内存中的某些内容也会一直被占用

这不是像这个问题中那样的速度问题。似乎记忆永远不会被回收

我能做些什么来从字典中删除条目,而不仅仅是用(null,null)对填充它?
还有什么我需要检查的吗?

看起来您需要定期回收该目录中的空间。您可以通过创建一个新字典来实现这一点:
newdictionary(oldDict)
。确保以线程安全的方式执行此操作


什么时候做?无论是在计时器的滴答声(60秒?)上,还是在发生特定次数的写入(100k?)时(您需要保留一个修改计数器)。

字典将项存储在哈希表中。为此,在内部使用了一个数组。由于哈希表的工作方式,此数组必须始终大于存储的实际项数(至少大30%)。Microsoft使用72%的负载系数,即至少28%的阵列为空(请参阅,特别是 因此,null/null条目可以表示这个空闲空间

如果阵列太小,它将自动增长;但是,删除项时,阵列不会收缩,但插入新项时应重新使用将释放的空间

如果您控制此词典,您可以尝试重新创建它以缩小它:

theDict = new Dictionary<TKey, IEnumerable<KeyValuePair<TKey2, TVal>>>(theDict);
theDict=新词典(theDict);
但问题可能来自实际(非空)条目。您的字典是静态的,因此垃圾收集器不会自动回收,除非您为它分配另一个字典或
null
theDict=new…
theDict=null
)。这只适用于静态词典本身,而不适用于其条目。只要对已删除条目的引用存在于其他地方,它们就会持续存在。GC将回收任何不能通过引用访问的对象(早期或后期)。不管这个对象是否声明为静态的,都没有区别。对象本身不是静态的,只是它们的引用



正如@RobertTausig善意地指出的那样,自从.NET Core 2.1以来,
就有了新的
字典.trimOverse()
,这是您实际上想要的,但在当时并不存在。

解决方案可以是在静态字典上调用()方法。
这样,对词典的引用将保持可用,但包含的对象将被释放。

+!:为了做适当的研究和写一个好问题。
List
有一个
trimOverse()
方法,
Dictionary
不幸地没有。我认为这是一个简单的分数:)调用Dictionary.Clear()有什么区别吗?@C.Evenhuis:我想用
字典
的性能换取
列表
,但这是个好主意。尽管其他人似乎对此感兴趣:@Alex:我试着调用
Clear()
,并检查了操作是否真的发生,但它不会随着所描述的行为而改变。谢谢你提供的信息,事情对我来说变得更清楚了。虽然我看到了可用空闲内存的优点,但我仍然希望以您和@usr建议的方式缩小它。当我想做的时候,我必须更好地分析。@Olivier说当项目被删除时它不会收缩,这是否意味着内存仍将被使用?@SirajMansour,删除项目不会改变哈希表数组的大小。值类型键和值直接存储在此数组中。对于引用类型,只有引用(或删除项后的
null
)存储在数组中。此引用指向的对象内存可以由垃圾收集器回收,如果它们没有在其他地方引用。有人在评论中提到了这一点,我当时回答说,使用
Clear
方法并没有得到我想要的结果。