[英]System.Threading.Timer windows service memory leak
I have ac# console application running as a windows service. 我有一个作为Windows服务运行的ac#控制台应用程序。 The main thread of the application uses a System.Threading.Timer
to manage 'sweeps' of a database. 应用程序的主线程使用System.Threading.Timer
来管理数据库的“扫描”。 When the sweep starts on timer tick, the timer creates an object to find work in the database, and that object raises an event when work is found to spawn off the job into another thread. 当扫描在计时器滴答声中开始时,计时器将创建一个对象以在数据库中查找工作,并且当发现有将工作派生到另一个线程中的对象时,该对象将引发一个事件。
I appear to be suffering a memory leak, and my limited windbg
abilities querying memory dumps has me thinking that the timer is not releasing something/itself to GC. 我似乎正在遭受内存泄漏,而我有限的查询内存转储的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[]
Simplified and condensed code: 简化的代码:
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
}
As commented above, i don't think this is a traditional event handler leak, and windbg
above has only this one massive entry at the bottom of !dumpheap -stat
for System.Object[]
. 如上所述,我认为这不是传统的事件处理程序泄漏,并且上面的windbg
仅在System.Object[]
的!dumpheap -stat
底部有一个大型条目。
Using jetBrains dotMemory I was able to determine that the handle open was from a line of code being called from referenced managed code down the stack in the job.Execute()
. 使用jetBrains dotMemory,我可以确定打开的句柄是从job.Execute()
堆栈中的引用托管代码调用的代码行中。 It was setting a delegate globally and causing ServerCertificateValidationCallback
to pin a handle and never release. 这是在全局设置委托,并导致ServerCertificateValidationCallback
固定句柄并且从不释放。
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => { };
Feels like it behaves in the "short term publisher, long term subscriber" classic memory leak fashion, as the parent object of the constructor calling this line was disposed shortly after. 感觉就像它在“短期发布者,长期订阅者”经典内存泄漏方式中一样,因为构造函数的父对象调用此行不久之后就被处置了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.