.NET 3.5 Windows 服务的 GC 句柄数 (#) 不断增长的根本原因是什么?
我有一个在 .NET Framework 3.5 上运行的 C# Windows 服务,该服务显示出不断增长的 GC 句柄数量(使用 Windows Server 2003 上的系统监视器可以看到)。
我已确保所有资源都得到正确处理,并且我的代码中没有终结器。
“大对象堆大小”和“所有堆中的字节数”相对静态,我可以看到“GC 中的%时间”显示正在发生垃圾收集。
“私有字节”计数器也在增加。
此症状导致任务管理器中的“内存使用量”每天增长约 35 MB,这是不可接受的,因为该服务基本上是针对 Oracle 10g 运行一个简单的 SELECT 查询,并每 5 秒使用 .NET TraceSources。 可能值得一提的是,TraceSource 使用 .NET Listeners 对象输出到 Windows 事件日志和文本文件。
有谁知道为什么“# GC Handles”不断增加,因为我相信这与我的“内存使用量”增加有关?
I have a C# Windows Service running on the .NET Framework 3.5 that is exhibiting a constantly growing number of GC Handles (seen using System Monitor on Windows Server 2003).
I have ensured that all resources are disposed of correctly, and have no Finalisers in my code.
The 'Large Object Heap size', and '# Bytes in all Heaps' are comparitively static, and I can see the '% Time in GC' is showing that Garbage collections are occurring.
The 'Private Bytes' counter is also increasing.
This symptom is causing my 'Memory Usage' in Task Manager to grow at around 35 MB per day, which is unacceptable as the Service is basically running a simple SELECT query against Oracle 10g and using .NET TraceSources every 5 seconds. It is probably worth mentioning that the TraceSource outputs to the Windows Event Log AND a text file using the .NET Listeners objects.
Does anyone know why the '# GC Handles' is constantly increasing, as I believe this is related to my increase in 'Memory Usage'?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
好的 - 排序了。
检查 .NET TraceSource 类的源代码后,发现根据设计,它拥有 2 个 WeakReferences 列表 - 1 个用于 TraceSource 对象,另一个用于 Switches。
它这样做是为了支持其 RefreshAll 方法。
我必须使用反射来手动清除这些列表。 所以,我不能再安全地使用 RefreshAll 方法,但至少我不再有 Private Bytes 和 GC Handles 的增长。
要重现该问题,只需创建整个 TraceSource 对象负载并关闭它们 - 您可以看到“泄漏”。
OK - sorted it.
After examining the source code for the .NET TraceSource class, it appears that, by design, it owns 2 lists of WeakReferences - 1 for the TraceSource objects, and one for the Switches.
It does this to support its RefreshAll method.
I had to use Reflection to manually clear out these lists. So, I cannot use the RefreshAll method safely any more, but at least I don't have growth in Private Bytes and GC Handles any more.
To reproduce the problem, just create a whole load of TraceSource objects and close them - you can see the "leak".
您没有释放代码正确引用的非托管资源。
您熟悉固定语句吗? 它可以固定内存,以便以不安全的方式对其进行访问。 然而,还有另一种方法可以做到这一点,我们认为这种方法可能不安全。
上述类型的代码正是可能导致您的问题类型的原因。 如果您没有显式地“.Free()”此固定内存,您将不会最终对该对象进行垃圾收集,并且会出现内存泄漏。
我的猜测是,类似的事情也发生在您的 Oracle 10g 提供程序中,除非您知道您正在做其他可能会泄漏内存的事情。
You're not releasing unmanaged resources being referenced by your code properly.
Are you familiar with the fixed statement? It can pin memory so that it can be accessed in an unsafe manner. However, there's another way to do that which we could argue is presumable unsafe.
The above type of code is exactly what could cause your type of problem. If you don't explicitly '.Free()' this pinned memory you'll not end up garbage collecting this object and you'll have a memory leak.
My guess is that a similar thing like this is happening with your Oracle 10g provider, unless you know you're doing something else which could potentially leak memory.
不管怎样,我们已经在 .NET 4.0 中为 TraceSource 和 Switch 修复了这个问题。
我们仍然认为最好的做法是不要创建一堆不同的 TraceSource 实例(而是为每个源创建一个静态实例并跨线程共享它们),但在某些情况下,如果您使用的是第三方库,则这是不可能的你无法修复。
For what it's worth, we've fixed this issue in .NET 4.0 for both TraceSource and Switch.
We still consider it a best practice to not create a bunch of different instances of TraceSource (rather create one static instance per source and share them across threads) but in some cases this isn't possible where you're using a third party library that you can't fix.
您使用 ODP.Net 吗?
请记住,ODP.Net 不是完全托管的,并且也有一个本机组件。
您是否使用任何其他本机资源,例如 ActiveDirectory 等。请记住,即使您有 .Net 程序集,对于 AD 等内容来说,它也是 COM 上的一个薄层。 我在我使用的 AD 代码中发现了大量内存泄漏。 不过,我的 ODP.Net 没有出现内存问题,而且我公司的企业服务是使用 ODP.Net 运行的。
Are you using ODP.Net ?
Remember ODP.Net is not fully managed and has a native component as well.
Do you use any other native resources, eg ActiveDirectory etc. Remember even if you have .Net assemblies it is a thin layer over COM for stuff like AD. I have seen massive memory leaks in AD code I used. I have not had memory issue with ODP.Net though and my company's enterprise service runs with ODP.Net.
这个调试经验的链接应该添加到这个讨论中。 它补充了@thehowler 发布的解决方法。
基本上,TraceSource 的每个新分配都会添加到不被垃圾收集的 WeakReference 列表中。
This link to a debugging experience should add to this discussion. It complements the workaround posted by @thehowler.
http://www.wintellect.com/blogs/jrobbins/is-that-a-weakreference-in-your-gen-2-or-are-you-just-glad-to-see-me
Basically, every new allocation of a TraceSource adds to a WeakReference list that is not garbage collected.