C# 单例中可能存在内存泄漏?

C# 单例中可能存在内存泄漏?,c#,.net,memory-leaks,producer-consumer,C#,.net,Memory Leaks,Producer Consumer,我以前问过这个问题,但没有真正的答案。有人能帮忙吗? 我在一个单例中分析下面的代码,发现很多Rate对象(List)都保存在内存中,尽管我清除了它们 protected void FetchingRates() { int count = 0; while (true) { try { if (m_RatesQueue.Count > 0) { List<RateLog> temp = null;

我以前问过这个问题,但没有真正的答案。有人能帮忙吗? 我在一个单例中分析下面的代码,发现很多Rate对象(
List
)都保存在内存中,尽管我清除了它们

protected void FetchingRates()
{
  int count = 0;

  while (true)
  {
    try
    {
      if (m_RatesQueue.Count > 0)
      {
        List<RateLog> temp = null;

        lock (m_RatesQueue)
        {
          temp = new List<RateLog>();
          temp.AddRange(m_RatesQueue);
          m_RatesQueue.Clear();
        }

        foreach (RateLog item in temp)
        {
          m_ConnectionDataAccess.InsertRateLog(item);
        }

        temp.Clear();
        temp = null;
      }
      count++;
      Thread.Sleep(int.Parse(ConfigurationManager.AppSettings["RatesIntreval"].ToString()));
    }
    catch (Exception ex)
    {  
      Logger.Log(ex);                 
    }
  }
} 
工作人员将速率日志插入数据库,如下所示:

 internal int InsertRateLog(RateLog item)
    {
        try
        {
            SqlCommand dbc = GetStoredProcCommand("InsertRateMonitoring");
            if (dbc == null)
                return 0;
            dbc.Parameters.Add(new SqlParameter("@HostName", item.HostName));
            dbc.Parameters.Add(new SqlParameter("@RateType", item.RateType));
            dbc.Parameters.Add(new SqlParameter("@LastUpdated", item.LastUpdated));
            return ExecuteNonQuery(dbc);
        }
        catch (Exception ex)
        {
            Logger.Log(ex);
            return 0;
        }
    }

有人看到可能的内存泄漏吗?

temp
创建移到循环之外如何。您可能不允许GC进行清理

protected void FetchingRates()
{
  int count = 0;
  List<RateLog> temp = new List<RateLog>();

  while (true)
  {
    try
    {
      if (m_RatesQueue.Count > 0)
      {    
        lock (m_RatesQueue)
        {
          temp.AddRange(m_RatesQueue);
          m_RatesQueue.Clear();
        }

        foreach (RateLog item in temp)
        {
          m_ConnectionDataAccess.InsertRateLog(item);
        }

        temp.Clear();
      }
      count++;
      Thread.Sleep(int.Parse(ConfigurationManager.AppSettings["RatesIntreval"].ToString()));
    }
    catch (Exception ex)
    {                   
    }
  }
} 
protectedvoid FetchingRates()
{
整数计数=0;
列表温度=新列表();
while(true)
{
尝试
{
如果(m_RatesQueue.Count>0)
{    
锁(m_RatesQueue)
{
温度范围(m_RatesQueue);
m_RatesQueue.Clear();
}
foreach(临时中的费率记录项)
{
m_ConnectionDataAccess.InsertRateLog(项目);
}
温度清除();
}
计数++;
Sleep(int.Parse(ConfigurationManager.AppSettings[“RatesIntreval”].ToString());
}
捕获(例外情况除外)
{                   
}
}
} 

temp.Clear()
之后,您可以尝试添加
GC.Collect()。这不应该是永久性的解决方案,但可以用于分析,以查看对象是否最终得到清理。如果没有,那么可能仍然有引用或事件附加在某个地方。

temp
创建移动到循环之外如何。您可能不允许GC进行清理

protected void FetchingRates()
{
  int count = 0;
  List<RateLog> temp = new List<RateLog>();

  while (true)
  {
    try
    {
      if (m_RatesQueue.Count > 0)
      {    
        lock (m_RatesQueue)
        {
          temp.AddRange(m_RatesQueue);
          m_RatesQueue.Clear();
        }

        foreach (RateLog item in temp)
        {
          m_ConnectionDataAccess.InsertRateLog(item);
        }

        temp.Clear();
      }
      count++;
      Thread.Sleep(int.Parse(ConfigurationManager.AppSettings["RatesIntreval"].ToString()));
    }
    catch (Exception ex)
    {                   
    }
  }
} 
protectedvoid FetchingRates()
{
整数计数=0;
列表温度=新列表();
while(true)
{
尝试
{
如果(m_RatesQueue.Count>0)
{    
锁(m_RatesQueue)
{
温度范围(m_RatesQueue);
m_RatesQueue.Clear();
}
foreach(临时中的费率记录项)
{
m_ConnectionDataAccess.InsertRateLog(项目);
}
温度清除();
}
计数++;
Sleep(int.Parse(ConfigurationManager.AppSettings[“RatesIntreval”].ToString());
}
捕获(例外情况除外)
{                   
}
}
} 
temp.Clear()
之后,您可以尝试添加
GC.Collect()。这不应该是永久性的解决方案,但可以用于分析,以查看对象是否最终得到清理。如果没有,则可能仍有引用或事件附加在某处。

Clear()函数解构列表。但是RateLog实例呢?他们的解构器叫什么?锁呢,也许这可以防止删除RateLog。

Clear()函数解构列表。但是RateLog实例呢?他们的解构器叫什么?锁呢,也许这可以防止删除RateLog

  • 我希望您正在正确处理ADO.NET对象。(这只是一种良好的做法。)
  • 任何错误的引用都会阻止GC收集您的
    RateLog
    对象
  • 我建议您从创建
    RateLog
    对象的位置开始查看代码,并记下引用的所有位置。这里有一些要考虑的事情。< /P>
  • RateLog
    对象是否订阅了任何事件
  • 您是否将
    RateLog
    对象的集合保存在静态类中的某个位置
  • 您还应该考虑将所有线程安全样板封装在类中。

    public sealed class WorkQueue<T>
    {
        private readonly System.Collections.Generic.Queue<T> _queue = new System.Collections.Generic.Queue<T>();
        private readonly object _lock = new object();
    
        public void Put(T item)
        {
            lock (_lock)
            {
                _queue.Enqueue(item);
            }
        }
    
    
        public bool TryGet(out T[] items)
        {
            if (_queue.Count > 0)
            {
                lock (_lock)
                {
                    if (_queue.Count > 0)
                    {
                        items = _queue.ToArray();
                        _queue.Clear();
                        return true;
                    }
                }
            }
    
            items = null;
            return false;
        }
    }
    
    公共密封类工作队列
    {
    private readonly System.Collections.Generic.Queue _Queue=new System.Collections.Generic.Queue();
    私有只读对象_lock=新对象();
    公众认股权证(T项)
    {
    锁
    {
    _排队。排队(项目);
    }
    }
    公共bool TryGet(out T[]项)
    {
    如果(_queue.Count>0)
    {
    锁
    {
    如果(_queue.Count>0)
    {
    items=_queue.ToArray();
    _queue.Clear();
    返回true;
    }
    }
    }
    items=null;
    返回false;
    }
    }
    
    这将使您的代码更加清晰:

    protected void FetchingRates()
    {
        int ratesInterval = int.Parse(ConfigurationManager.AppSettings["RatesIntreval"].ToString());
        int count = 0;
        var queue = new WorkQueue<RateLog>();
    
        while (true)
        {
            try
            {
                var items = default(RateLog[]);
                if (queue.TryGet(out items))
                {
                    foreach (var item in items)
                    {
                        m_ConnectionDataAccess.InsertRateLog(item);
                    }
                }
            }
            catch (Exception ex)
            {  
                Logger.Log(ex);                 
            }
    
            Thread.Sleep(ratesInterval);
            count++;
        }
    } 
    
    protectedvoid FetchingRates()
    {
    int-ratesInterval=int.Parse(ConfigurationManager.AppSettings[“RatesIntreval”].ToString());
    整数计数=0;
    var queue=新工作队列();
    while(true)
    {
    尝试
    {
    var项目=默认值(RateLog[]);
    if(queue.TryGet(out项))
    {
    foreach(项目中的var项目)
    {
    m_ConnectionDataAccess.InsertRateLog(项目);
    }
    }
    }
    捕获(例外情况除外)
    {  
    Logger.Log(ex);
    }
    线程。睡眠(比率为0);
    计数++;
    }
    } 
    
  • 我希望您正在正确处理ADO.NET对象。(这只是一种良好的做法。)
  • 任何错误的引用都会阻止GC收集您的
    RateLog
    对象
  • 我建议您从创建
    RateLog
    对象的位置开始查看代码,并记下引用的所有位置。这里有一些要考虑的事情。< /P>
  • RateLog
    对象是否订阅了任何事件
  • 您是否将
    RateLog
    对象的集合保存在静态类中的某个位置
  • 您还应该考虑将所有线程安全样板封装在类中。

    public sealed class WorkQueue<T>
    {
        private readonly System.Collections.Generic.Queue<T> _queue = new System.Collections.Generic.Queue<T>();
        private readonly object _lock = new object();
    
        public void Put(T item)
        {
            lock (_lock)
            {
                _queue.Enqueue(item);
            }
        }
    
    
        public bool TryGet(out T[] items)
        {
            if (_queue.Count > 0)
            {
                lock (_lock)
                {
                    if (_queue.Count > 0)
                    {
                        items = _queue.ToArray();
                        _queue.Clear();
                        return true;
                    }
                }
            }
    
            items = null;
            return false;
        }
    }
    
    公共密封类工作队列
    {
    private readonly System.Collections.Generic.Queue _Queue=new System.Collections.Generic.Queue();
    私有只读对象_lock=新对象();
    公众认股权证(T项)
    {
    锁
    {
    _排队。排队(项目);
    }
    }
    公共bool TryGet(out T[]项)
    {
    如果(_queue.Count>0)
    {
    锁