Gen2收集不总是收集坏物? [英] Gen2 collection not always collecting dead objects?

查看:45
本文介绍了Gen2收集不总是收集坏物?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在过去的几天中,通过监视全新.NET 4.5服务器应用程序中所有堆的 CLR #Bytes 性能计数器,我可以注意到一种模式,使我认为Gen2集合不是总是收集死物,但是我很难理解到底发生了什么.

By monitoring the CLR #Bytes in all Heaps performance counter of a brand new .NET 4.5 server application over the last few days, I can notice a pattern that makes me think that Gen2 collection is not always collecting dead objects, but I am having trouble understanding what exactly is going on.

服务器应用程序正在使用Server GC/后台在 .NET Framework 4.5.1中运行.

Server application is running in .NET Framework 4.5.1 using Server GC / Background.

这是作为Windows服务托管的控制台应用程序(在Topshelf框架的帮助下)

This is a console application hosted as a Windows Service (with the help of Topshelf framework)

服务器应用程序正在处理消息,因此吞吐量目前仍相当稳定.

The server application is processing messages, and the throughput is somehow pretty constant for now.

通过查看所有堆中的 CLR #Bytes 图表,我看到的是内存开始大约18MB,然后在大约20-24小时内增长到35MB(第二代介于20-30之间)时间段内的数据集),然后突然下降到标称值18MB,然后在20-24小时内再次增长到〜35MB,然后又下降到18MB,依此类推(我可以看到模式在重复该应用程序已运行的最近6天)...内存的增长不是线性的,要增加10MB大约需要5个小时,然后剩余的10 MB左右需要15-17个小时.

What I can see looking at the graph of CLR #Bytes in all Heaps is that the memory started arround 18MB then growing up to 35MB on approx 20-24 hours (with between 20-30 Gen2 collections during that time frame), and then all of a sudden dropping back to nominal value of 18MB, then growing again up to ~35MB over 20-24 hours and dropping back to 18MB, and so on (I can see the pattern repeating over the last 6 days the app is now running) ... The growing of memory is not linear, it takes approx 5 hours to grow by 10MB and then 15-17 hours for the remaining 10 MB or so.

通过查看#Gen0/#Gen1/#Gen2集合的性能计数器,我可以看到一堆Gen2集合在20-24小时内进行(也许是围绕)30),但没有一个会使内存降回标称的18MB.但是,奇怪的是使用外部工具强制执行GC(在我的情况下为Perfview),然后我看到 #Induced GC 上升了1(调用了GC.Collect,所以这很正常),然后内存立即恢复为正常的18MB.

Thing is that I can see by looking at perfmon counters for #Gen0/#Gen1/#Gen2 collections that a bunch of Gen2 collections are going on during the 20-24 hours period (maybe arround 30) and none of them makes the memory drop back to nominal 18MB. However, what is strange is by using an external tool to force a GC (Perfview in my case), then I can see #Induced GC going up by 1 (GC.Collect was called so this is normal) and immediately the memory is going back to nominal 18MB.

这使我想到#Gen2集合的性能计数器不正确,并且在20-22小时左右后才发生一个Gen2集合(我真的不这么认为),或者Gen2集合不正确总是收集死对象(似乎更合理)...但是在那种情况下,为什么要通过GC.Collect强制GC,但在生命周期中显式调用GC.Collect与自动触发收集之间的区别是什么?该应用程序.

Which leads me into thinking that either the perfmon counter for #Gen2 collections is not right and only a single Gen2 collection happens after 20-22hours or so (meeehhh I really don't think so) or that the Gen2 collection does not always collect dead objects (seems more plausible) ... but in that case why would forcing a GC via GC.Collect do the trick, what would be the difference between explicitely calling into GC.Collect, v.s automatic triggered collections during the lifetime of the application.

我肯定有很好的解释,但是从我发现的有关GC的其他文档来源中得知-太少了:(-在任何情况下,Gen2集合均收集死对象.因此,文档可能不是最新的,或者我看错了...欢迎任何解释,谢谢!

I am sure there is a very good explanation but from the different source of documentation I have found about GC -too few :(- a Gen2 collection does collect dead objects in any case. So maybe docs are not up to date or I have misread ... Any explanation is welcome. Thanks !

:请查看此为期4天的 #Bytes in all heaps 图的屏幕截图

EDIT : Please see this screenshot of the #Bytes in all heaps graph over 4 days

(点击查看大图)

这比尝试在脑海中绘制图形要容易.您在图表上可以看到的是我上面所说的...内存在20-24小时内增加(在此时间范围内增加了20-30个Gen2集合),直到达到〜35MB,然后突然下降.您会注意到,在图的末尾,通过外部工具触发的诱导GC,立即将内存降回了标称值.

this is easier than trying to graph things in your head. What you can see on the graph is what I said above... memory increasing over 20-24hours (and 20-30 Gen2 collections during that time frame) until reaching ~35MB then dropping all of a sudden. You will note at the end of the graph, the induced GC I triggered via an external tool, immediately dropping back memory to nominal.

编辑#2:我在代码中做了很多清洁工作,主要是关于终结器.我有很多类都持有对一次性类型的引用,因此我不得不在这些类型上实现 IDisposable .但是,无论如何,我还是被一些文章误导为使用Finalizer实现Diposable模式.在阅读了一些MSDN文档之后,我了解到,只有在类型持有本地资源本身时才需要终结器(并且在这种情况下,可以使用SafeHandle避免这种情况).因此,我从所有这些类型中删除了所有终结器.代码中还有一些其他用途,但主要是业务逻辑,与".NET框架"无关.现在的图形非常不同,这是几天来大约20MB的一条直线,正好是我期望看到的!因此,问题现在已解决,但是我仍然不知道问题出在什么方面……这似乎与终结器有关,但即使我们没有打电话给Dispose,也仍然无法解释我注意到的问题.(true)-禁止finalizer-,finalizer线程应该在收集之间插入,而不是每20-24小时一次?考虑到我们现在已经摆脱了这个问题,需要一段时间才能返回到越野车"版本并再次再现它.我可能会尝试一段时间,然后再探究它的底部.

EDIT #2 : I made a lot of cleaning in the code, mainly regarding finalizers. I had a lot of classes that were holding reference to disposable types, so I had to implement IDisposable on these types. However I was misguided by some articles into implementing the Diposable pattern with a Finalizer in any case. After reading some MSDN documentation I came to understand that a finalizer was only required when the type was holding native resources itself (and still in that case this could be avoided with SafeHandle). So I removed all finalizers from all these types. There were some other modications in the code, but mainly business logic, nothing ".NET framework" related. Now the graph is very different, this is a flat line arround 20MB for days now ... exactly what I was expecting to see ! So the problem is now fixed, however I still have no idea what was the problem due to ... It seems like it might have been related to finalizers but still does not explain what I was noticing, even if we weren't calling Dispose(true) -suppressing finalizer-, the finalizer thread is supposed to kick in between collection and not every 20-24 hours ?! Considering we have now moved away from the problem, it will take time to come back to the "buggy" version and reproduce it again. I may try to do it some time though and go to the bottom of it.

添加了Gen2集合图(点击查看大图)

Added Gen2 collection graph (Click for larger view)

推荐答案

来自

http://msdn.microsoft.com/en-us/library/ee787088%28v = VS.110%29.aspx#workstation_and_server_garbage_collection

垃圾收集的条件

当以下情况之一发生时,将发生垃圾收集正确:

Conditions for a garbage collection

Garbage collection occurs when one of the following conditions is true:

  • 系统的物理内存不足.

  • The system has low physical memory.

托管堆上分配的对象使用的内存超过了可接受的阈值.这个阈值是连续的在过程运行时进行调整.

The memory that is used by allocated objects on the managed heap surpasses an acceptable threshold. This threshold is continuously adjusted as the process runs.

将调用GC.Collect方法.在几乎所有情况下,您不必调用此方法,因为垃圾收集器会运行不断地.此方法主要用于特殊情况和测试.

The GC.Collect method is called. In almost all cases, you do not have to call this method, because the garbage collector runs continuously. This method is primarily used for unique situations and testing.

看来您正在达到第二名,而35是门槛.如果35太大,您应该可以将阈值配置为其他值.

It seems that you are hitting the 2nd one and 35 is the threshold. You should be able to configure the threshold to something else if 35 is to large.

第2代集合没有什么特别之处,可以使它们偏离这些规则.(cf https://stackoverflow.com/a/8582251/215752 )

There isn't anything special about gen2 collections that would cause them to deviate from these rules. (cf https://stackoverflow.com/a/8582251/215752)

这篇关于Gen2收集不总是收集坏物?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆