【发布时间】:2011-05-03 16:38:38
【问题描述】:
我编写了一个 .Net (2.0) Windows 服务,用于向用户发送寻呼机消息(通过串行端口连接到第 3 方硬件)。
服务会定期查询数据库 (OSI PI Historian),解析值并根据解析后的值决定是否发送消息。
服务使用查找对象(其值来自 SQL Server 数据库并每分钟刷新一次)来获取用户地址值和要发送的消息字符串。
该服务使用多个 Threading.Timers 来触发定期数据库调用和消息发送。
该服务安装在安装了 .Net 2 SP2 的 Windows 2003 机器上。
该服务可以正常运行大约一周,然后挂起。日志中没有记录异常 (log4net)。
我从服务器获取了一些转储,它们都表现出相同的特征 - 一个线程触发 GC 但无限期挂起:
06aaf06c 7c827b99 77e61d1e 00004acc 00000000 ntdll!KiFastSystemCallRet
06aaf070 77e61d1e 00004acc 00000000 00000000 ntdll!ZwWaitForSingleObject+0xc
06aaf0e0 79e8c5f9 00004acc ffffffff 00000000 kernel32!WaitForSingleObjectEx+0xac
06aaf124 79e8c52f 00004acc ffffffff 00000000 mscorwks!PEImage::LoadImage+0x1af
06aaf174 79e8c54e ffffffff 00000000 00000000 mscorwks!CLREvent::WaitEx+0x117
06aaf188 79f2f88f ffffffff 00000000 00000000 mscorwks!CLREvent::Wait+0x17
06aaf1a8 79f2f8ca 7a3b9020 00000000 ffffffff mscorwks!SVR::gc_heap::user_thread_wait+0x50
06aaf1b8 79f2f806 00000000 7a3b8b18 00080101 mscorwks!WKS::gc_heap::wait_to_proceed+0xe
06aaf1cc 79f92f5a 00000000 00000000 00000000 mscorwks!WKS::gc_heap::garbage_collect+0x247
06aaf1f8 79f94e26 00000000 00000000 00000030 mscorwks!WKS::GCHeap::GarbageCollectGeneration+0x1a9
06aaf284 79f926ce 052c75c8 00000030 00000000 mscorwks!WKS::gc_heap::try_allocate_more_space+0x15b
06aaf298 79f92769 052c75c8 00000030 00000000 mscorwks!WKS::gc_heap::allocate_more_space+0x11
06aaf2b8 79e73291 052c75c8 0000002e 00000000 mscorwks!WKS::GCHeap::Alloc+0x3b
06aaf2d4 79e7d8d4 0000002e 00000000 00000000 mscorwks!Alloc+0x60
06aaf310 79e99056 0000000f b456b75e 00001ce3 mscorwks!SlowAllocateString+0x29
06aaf3b4 792bb2c1 00000000 0108082b 00001f40 mscorwks!FramedAllocateString+0xa1
Stack shortened for bravity...
托管堆栈:
ESP EIP
06aaf364 7c82847c [HelperMethodFrame: 06aaf364]
06aaf3bc 792bb2c1 System.String.CreateStringFromEncoding(Byte*, Int32, System.Text.Encoding)
06aaf3dc 792aaf2a System.Text.EncodingNLS.GetString(Byte[], Int32, Int32)
06aaf3fc 6522d131 System.Data.SqlClient.TdsParserStateObject.ReadStringWithEncoding(Int32, System.Text.Encoding, Boolean)
06aaf41c 656ca93e System.Data.SqlClient.TdsParser.ReadSqlStringValue(System.Data.SqlClient.SqlBuffer, Byte, Int32, System.Text.Encoding, Boolean, System.Data.SqlClient.TdsParserStateObject)
06aaf448 6522d925 System.Data.SqlClient.TdsParser.ReadSqlValue(System.Data.SqlClient.SqlBuffer, System.Data.SqlClient.SqlMetaDataPriv, Int32, System.Data.SqlClient.TdsParserStateObject)
06aaf474 656208b7 System.Data.SqlClient.SqlDataReader.ReadColumnData()
06aaf484 65620962 System.Data.SqlClient.SqlDataReader.ReadColumn(Int32, Boolean)
06aaf4b4 65221415 System.Data.SqlClient.SqlDataReader.GetValueInternal(Int32)
06aaf4c8 652213af System.Data.SqlClient.SqlDataReader.GetValue(Int32)
06aaf4f8 65220aec System.Data.SqlClient.SqlDataReader.get_Item(System.String)
06aaf504 03616b81 AlarmEventCollator.DataAccess.GetAllAlarmDetails()
06aaf564 03616a28 AlarmEventCollator.AlarmBuilder.buildLookups()
06aaf590 0361aa89 AlarmEventCollator.AlarmBuilder.pollLookups(System.Object)
06aaf5d0 792a83ff System.Threading._TimerCallback.TimerCallback_Context(System.Object)
06aaf5d8 792e019f System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
06aaf5f0 792a836b System.Threading._TimerCallback.PerformTimerCallback(System.Object)
06aaf77c 79e71b4c [GCFrame: 06aaf77c]
GC通常发生在数据库解析方法中。所有其他托管线程似乎都挂起 - 这与 GC 进程一致。
我将不胜感激任何指针。可根据要求提供更多信息。
【问题讨论】:
-
您正在处理许多不同的连接(SQL 和串行)。 GC 是否能够收集所有旧项目,或者是否存在内存中会导致内存使用量增加的东西(如果您不小心,静态类或串行连接可能会导致这种情况)?你有没有观察内存使用情况,确定它不是因为内存太满而 GC 无法运行那么简单(愚蠢的问题,我知道,但我必须问)?
-
另外,请确保在完成所有实现 IDisposable 的对象后立即处理它们。
-
我不相信内存中有任何过多的大对象 - 故障转储报告 GC 堆大小为 22mb。据我所知,所有 IDisposible 对象都被释放了。
-
另一个可能有助于 GC 和多线程的线程:social.msdn.microsoft.com/forums/en-US/clr/thread/… 顺便说一句,“线程触发 GC”是什么意思。您是明确调用 GC 还是 GC 是由“自然原因”触发的?
-
除了 John 所说的之外,非托管类应该定义终结器以便正确处理。
标签: c# .net windows-services garbage-collection