C# GC终结器队列中存在大量对象

C# GC终结器队列中存在大量对象,c#,.net,garbage-collection,server,C#,.net,Garbage Collection,Server,我正在调查我们的服务器.NET应用程序内存占用的缓慢而稳定的增长。为了便于调查,我对6个模拟真实负载的客户端进行了压力测试,这些客户端反复重复相同的使用模式。 当我通宵运行时,我可以看到内存占用增加了大约几百MB。在分析和比较相隔12小时的服务器内存快照后,发现大部分差异是由于ReaderWriterLock实例在终结器队列中等待造成的。他们中有超过60万人 通过分析我的代码并查看GC根目录,可以发现所有的ReaderWriterLock活动实例都来自我们软件中的DataSet实例。因此,我尝试

我正在调查我们的服务器.NET应用程序内存占用的缓慢而稳定的增长。为了便于调查,我对6个模拟真实负载的客户端进行了压力测试,这些客户端反复重复相同的使用模式。 当我通宵运行时,我可以看到内存占用增加了大约几百MB。在分析和比较相隔12小时的服务器内存快照后,发现大部分差异是由于
ReaderWriterLock
实例在终结器队列中等待造成的。他们中有超过60万人

通过分析我的代码并查看GC根目录,可以发现所有的
ReaderWriterLock
活动实例都来自我们软件中的
DataSet
实例。因此,我尝试创建
DataSet
实例,以尽可能地消除它。在清理了一些代码并缓存了一些
DataSet
实例以避免不必要的分配之后,差异减少了约25%,但看起来它们的数量更多

我的问题是:

  • 为什么终结器队列中有这么多实例-不确定是什么导致了这种情况
  • 我会假设终结器队列的大小会对GC和整体应用程序性能产生负面影响(在一段时间后,它看起来很慢)
  • 我应该做什么来减少终结器队列的大小?对我不再需要的每个
    DataSet
    实例调用dispose

  • 请注意,我使用的是“服务器”模式GC,因为我们的服务器在不同的线程上并行处理请求。

    虽然我还没有弄清楚为什么终结器队列中有这么多的
    ReaderWriterLock
    实例,但我确实找到了解决问题的方法,并将它们处理掉了

    调用DataSet.Dispose没有帮助。因此,我已经开始重用现有的
    DataSet
    实例,而不是继续创建新实例,因为“有人说
    DataSet.Clear
    很慢”——从长远来看,这不是(如果有的话)。
    这种方法完全消除了终结器队列实例的问题。

    虽然我还没有弄清楚为什么终结器队列中有这么多的
    ReaderWriterLock
    实例,但我确实找到了解决问题的方法并将其清除

    调用DataSet.Dispose没有帮助。因此,我已经开始重用现有的
    DataSet
    实例,而不是继续创建新实例,因为“有人说
    DataSet.Clear
    很慢”——从长远来看,这不是(如果有的话)。
    这种方法完全消除了终结器队列实例的问题。

    除非内存压力,否则GC不会收集,你是说这是内存泄漏吗,或者只是有很多对象等待完成,没有内存压力来释放它们?@RonBeyer查看GC中的“%of time in GC”计数器看起来GC收集了很多,基本上服务器花费了将近一半的时间做GC(值一直徘徊在0-50-100)。也许我有太多的分配,GC无法跟上?除非有内存压力,否则GC不会收集,你是说这是内存泄漏,还是有很多对象等待完成,没有内存压力来释放它们?@RonBeyer看着GC计数器中的“%of time in GC”看起来GC收集了很多,基本上,服务器花费几乎一半的时间进行GC(值保持在0-50-100之间)。也许我有太多的分配,而GC在跟上时遇到了问题?如果您没有使用派生类,那么在
    数据集上调用
    Dispose()
    所做的唯一事情就是将其自身从
    站点中删除。如果容器有站点,则引发
    Disposed
    事件。如果您不使用派生类,则它甚至不会对其拥有的数据表调用
    Dispose()
    (顺便说一句,DataTable
    所做的就是从站点容器中删除并引发其
    Disposed
    事件)
    数据集上
    所做的是将其自身从
    站点中删除。容器
    如果有站点,则引发
    已处置事件。它甚至不会对其拥有的数据表调用
    Dispose()
    (顺便说一句,所有
    DataTable
    所做的只是从站点容器中删除并引发其
    Disposed
    事件)