我有一个作为Windows服务运行的c#控制台应用程序。该应用程序的主要线程使用System.Threading.Timer
来管理扫描'一个数据库。当计时器勾选开始扫描时,计时器会创建一个对象以在数据库中查找工作,并且当找到工作将作业产生到另一个线程时,该对象会引发一个事件。
我似乎正在遭受内存泄漏,而我查询内存转储的有限windbg
能力让我觉得计时器没有向GC释放某些东西。
windbg:
!dumpheap -type System.Object[]
...
02b01ae0 73a20cbc 32656
02b09a80 73a20cbc 4112
02b0e8e0 73a20cbc 16336
02b5bf88 73a20cbc 1040
02b5c3a8 73a20cbc 2064
10ee1010 73a20cbc 268435472
Statistics:
MT Count TotalSize Class Name
04210964 1 32 System.Func`2[[System.Type, mscorlib],[System.Func`2[[System.Object[], mscorlib],[Newtonsoft.Json.JsonConverter, Newtonsoft.Json]], mscorlib]]
7366a6a4 1 48 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Object[], mscorlib]]
04210a5c 1 48 System.Collections.Generic.Dictionary`2[[System.Type, mscorlib],[System.Func`2[[System.Object[], mscorlib],[Newtonsoft.Json.JsonConverter, Newtonsoft.Json]], mscorlib]]
73a20cbc 1194 268556916 System.Object[]
Total 1198 objects
0:000> !gcroot 10ee1010
Thread 2dfc:
04f1f70c 72db0687 System.Net.TimerThread.ThreadProc()
ebp+50: 04f1f710 (interior)
-> 02ac33a8 System.Object[]
-> 072a5a38 System.Net.ServerCertValidationCallback
-> 072a5a18 System.Net.Security.RemoteCertificateValidationCallback
-> 10ee1010 System.Object[]
简化和精简代码:
TimeSpan timerInterval = TimeSpan.FromSeconds(5);
static Timer t;
public void startTimer()
{
t = new System.Threading.Timer(TimerTick, null, TimeSpan.Zero, timerInterval);
}
public void TimerTick(Object TimerState)
{
//run each query sweep synchronously
t.Change(Timeout.Infinite, Timeout.Infinite);
List<Query> queries = GetQueries();
foreach (var query in queries)
{
var search = new QueryProcessor(query);
//short term publisher?
search.resultFoundEvent += QueryResultEventListener;
search.RunSearch();
}
t.Change(timerInterval, timerInterval);
}
public void RunJob(JobDetails job)
{
Task.Factory.StartNew(() => job.Execute(JobCallback));
}
//long term subscriber
public void QueryResultEventListener(object sender, FakeEventArgs e)
{
RunJob(e.jobdetails);
}
public void JobCallback(JobDetails jobsuccess)
{
//job was completed
}
如上所述,我不认为这是传统的事件处理程序泄漏,上面的windbg
只有!dumpheap -stat
底部System.Object[]
的{{1}}
答案 0 :(得分:1)
使用jetBrains dotMemory我能够确定句柄打开来自从job.Execute()
中的堆栈中引用的托管代码调用的一行代码。它正在全局设置一个委托,导致ServerCertificateValidationCallback
固定句柄并且永不释放。
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => { };
喜欢它的行为在短期出版商,长期用户和#34;经典的内存泄漏方式,因为调用此行的构造函数的父对象在不久后被处理掉。