我们有某种泄漏,其性质我不明白。 Gen0 / 1/2堆的大小不会增加,但是工作集会增加,直到我们OOM。
DebugDiag告诉我CLR.DLL拥有不断增长的内存,并告诉我我们有一个不断增长的终结器队列 - 数以万计的Texture2D(它是一个XNA应用程序)对象随着时间的推移而增加..但是没有分析器(dotTrace, Ants,CLR Profiler)可以找到这些对象 - 它们不会在堆中显示,而CLRProfiler声明它们永远不会被分配。
所以我查看WinDbg - 再一次,我可以看到一个不断增长的Finalizer队列,其中充满了Texture2D。 fReachable是空的,它声称所有这些对象都在堆上。
*0:038> !finalizequeue
SyncBlocks to be cleaned up: 0
MTA Interfaces to be released: 0
STA Interfaces to be released: 0
----------------------------------
generation 0 has 1881 finalizable objects (33e365b0->33e38314)
generation 1 has 41580 finalizable objects (33e0dc00->33e365b0)
generation 2 has 685816 finalizable objects (33b70020->33e0dc00)
Ready for finalization 0 objects (33e38314->33e38314)
MT Count TotalSize Class Name
......snip......
00ce67e0 726827 49424236 Microsoft.Xna.Framework.Graphics.Texture2D*
然后我查找那些726,000个实例,以便找到谁拥有它们。问题是dumpheap说只有218.这就是我所期望的以及托管分析师告诉我的内容。
*0:038> !dumpheap -stat -type Microsoft.Xna.Framework.Graphics.Texture2D
total 0 objects
Statistics:
MT Count TotalSize Class Name
00ce67e0 218 14824 Microsoft.Xna.Framework.Graphics.Texture2D
Total 218 objects*
那么终结器队列中的其他项目来自哪里?现在我怀疑随着内存分配的增长,内存分配的终结器队列越来越多,因此也就是OOM。 由于某种原因,好像这218个项目被多次添加到Finalizer队列中。
非常感谢
安迪
答案 0 :(得分:2)
为了完整性,这里发生了什么。
如果访问Device.Texture []集合,XNA会出现导致在Texture2D上调用ReRegisterForFinalize的问题。 Sunburn每帧都会访问此集合以解决另一个XNA问题,因此如果您有很多纹理,那么这可以非常快速地构建。
在XNA(Texture3D等)中有几个地方使用相同的模式,因此我假设您可以通过多种方式重现这一点。
由于没有XNA 5的迹象我们不得不解决它 - 我发现在访问集合后简单地调用SuppressFInalize会删除已添加的额外项目。我们认为它是安全的:-) Sunburn的人在他们的代码中添加了一个修复程序,我们希望这个问题会消失。
答案 1 :(得分:1)
是否可以将同一实例重新添加到finalize队列中?来自Object.Finalize上的文档:
Finalize在给定实例上仅自动调用一次,除非使用诸如GC.ReRegisterForFinalize和GC.SuppressFinalize之类的机制重新注册该对象。
这是唯一适合你在这里看到的解释。不知道为什么它会被重新注册以进行最终确定。