возможная утечка памяти в синглтоне? - PullRequest
0 голосов
/ 10 сентября 2010

Я задавал этот вопрос раньше без реального ответа. Кто-нибудь может помочь? Я профилировал приведенный ниже код внутри синглтона и обнаружил, что многие объекты Rate (List<Rate>) хранятся в памяти, хотя я их очищаю.

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);                 
    }
  }
} 

Вставка в очередь производится:

public void InsertLogRecord(RateLog msg)
{
  try
  {
    if (m_RatesQueue != null)
    {
      //lock (((ICollection)m_queue).SyncRoot)
      lock (m_RatesQueue)
      {
        //insert new job to the line and release the thread to continue working.
        m_RatesQueue.Add(msg);
      }
    }
  }
  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;
        }
    }

Кто-нибудь видит возможную утечку памяти?

Ответы [ 4 ]

2 голосов
/ 10 сентября 2010

Похоже, вы не избавляетесь от своего SqlCommand, который висит на RateLog.

2 голосов
/ 10 сентября 2010
  1. Надеюсь, вы правильно утилизируете объекты ADO.NET. (Это просто хорошая практика.)
  2. Любые случайные ссылки будут препятствовать тому, чтобы ваши RateLog объекты были собраны GC.

Я рекомендую вам просмотреть код, начиная с того, где создаются объекты RateLog, и записать все места, где хранится ссылка. Вот несколько вещей для рассмотрения.

  1. Подписаны ли объекты RateLog на какие-либо события?
  2. Вы храните коллекцию 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;
    }
}

Это сделает ваш код намного понятнее:

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++;
    }
} 
0 голосов
/ 10 сентября 2010

функция Clear () деконструирует список. Но как насчет экземпляров RateLog? Их деконструктор называется? Что касается блокировки, может быть, это предотвращает удаление RateLog.

0 голосов
/ 10 сентября 2010

Как насчет перемещения temp создания вне цикла. Вы, вероятно, не позволяете ГХ убирать.

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)
    {                   
    }
  }
} 

После temp.Clear() вы можете попробовать добавить GC.Collect();. Это НЕ должно быть постоянным решением, но может использоваться для вашего профилирования, чтобы увидеть, очищаются ли объекты в конце концов. Если нет, то где-то еще может быть ссылка или событие.

...