之前我没有问过这个问题。有人可以帮忙吗?
我在单例内部分析下面的代码,发现很多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);
}
}
worker将速率日志插入DB,如下所示:
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;
}
}
任何人都看到可能的内存泄漏?
答案 0 :(得分:2)
RateLog
个对象。我建议您从创建RateLog
对象的位置开始查看代码,并记下所有引用的位置。以下是一些需要考虑的事项。
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;
}
}
这将使您的代码更清晰:
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++;
}
}
答案 1 :(得分:2)
看起来您没有丢弃挂在RateLog上的SqlCommand
。
答案 2 :(得分: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)
{
}
}
}
在temp.Clear()
之后,您可以尝试添加GC.Collect();
。这不应该是永久的解决方案,但可以用于您的分析,以查看对象是否最终被清理。如果没有,那么某处可能仍然存在引用或事件。
答案 3 :(得分:0)
Clear()函数解构List。但是RateLog实例怎么样?他们的解构者被称为?锁定怎么样,这可能会阻止RateLog被删除。