Frage

Ich habe diese Frage gestellt, bevor ohne wirkliche Antwort. Kann jemand helfen? Ich bin die in einem Singleton unter Code Profilierung und festgestellt, dass viele Rate Objekte (List<Rate>) werden im Speicher gehalten, obwohl ich sie löschen.

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

Das Einfügen in die Warteschlange wird von:

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

Der Arbeiter Einsätze Rate log in DB wie folgt:

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

Jeder sieht einen möglichen Speicherverlust?

War es hilfreich?

Lösung

Sieht aus wie Sie Entsorgung nicht Ihrer SqlCommand, die auf eine RateLog hängt.

Andere Tipps

  1. Ich hoffe, dass Sie richtig die ADO.NET-Objekte werden zu entsorgen. (Dies ist einfach eine gute Praxis.)
  2. Jede Streu Referenzen Ihre RateLog Objekte halten von der GC gesammelt werden.

Ich empfehle Ihnen, Ihren Code durchschauen beginnen, wo die RateLog Objekte erstellt werden und zur Kenntnis nehmen von allen Orten eine Referenz gehalten wird. Hier sind einige Dinge zu beachten.

  1. Sind die RateLog auf alle Ereignisse abonniert Objekte?
  2. Sind Sie eine Sammlung von RateLog halten Objekte irgendwo in einer statischen Klasse sitzen?

Sie sollten auch alle Ihre Thread-Sicherheit vorformulierten in Klasse betrachten eingekapselt wird.

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

Dies wird Ihren Code viel klarer machen:

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

die Clear () Funktion dekonstruiert die Liste. Aber was ist mit den RateLog Instanzen? Ist ihr Deconstructor genannt? Was ist mit dem Schloss, vielleicht Dies verhindert, dass der RateLog von beeing gelöscht.

Wie wäre es die temp Schöpfung außerhalb der Schleife bewegt. Sie sind wahrscheinlich die GC nicht erlaubt bis zu reinigen.

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

Nach temp.Clear() können Sie versuchen GC.Collect(); hinzufügen. Dies sollte nicht die endgültige Lösung sein, aber könnte für Ihre Profilierung verwendet werden, um zu sehen, ob die Objekte schließlich gereinigt bekommen. Wenn nicht, dann könnte es noch eine Referenz sein oder Ereignis angebracht irgendwo.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top