Domanda

Ho chiesto questa domanda prima con nessuna vera risposta. Qualcuno può aiutarmi? Sto profiling il sottostante codice all'interno di un Singleton e ha scoperto che un sacco di oggetti Tasso (List<Rate>) vengono conservati in memoria anche se li ho chiaro.

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

L'inserimento alla coda è costituito da:

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

Il registro inserti lavoratore tasso in DB come segue:

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

Uno vede una possibile perdita di memoria?

È stato utile?

Soluzione

Sembra che tu non abbandonare definitivamente il proprio SqlCommand che incombe su un RateLog.

Altri suggerimenti

  1. Spero Prima di gettare correttamente gli oggetti ADO.NET. (Questo è semplicemente buona pratica.)
  2. Tutti i riferimenti randagi non mancherà di tenere i vostri oggetti RateLog di essere raccolto dal GC.

vi consiglio di guardare attraverso il vostro codice che inizia dove gli oggetti RateLog vengono creati e prendere nota di tutti i luoghi si svolge un riferimento. Qui ci sono alcune cose da considerare.

  1. sono gli oggetti RateLog sottoscritto eventi?
  2. Sei mantenendo una collezione di oggetti RateLog seduto da qualche parte in una classe statica?

Si dovrebbe anche considerare incapsulare tutto boilerplate la vostra sicurezza filo in classe.

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

Questo renderà il vostro codice molto più chiaro:

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

la funzione Clear () decostruisce la lista. Ma per quanto riguarda le istanze RateLog? È il loro decostruttore chiamato? Che dire del blocco, forse questo modo si evita che la RateLog da beeing cancellato.

Come sullo spostamento della creazione temp fuori del ciclo. Non siete probabilmente consente al GC per ripulire.

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

Dopo temp.Clear() si potrebbe provare ad aggiungere GC.Collect();. Questo non dovrebbe essere la soluzione definitiva, ma potrebbe essere utilizzato per la profilazione per vedere se gli oggetti vengono pulite fino alla fine. Se no, allora ci potrebbe essere ancora un qualche riferimento o evento associato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top