我想在我的OpenGL游戏中添加一个小的调试UI,它将经常使用各种调试选项/输出显示进行更新。我想要的一件事是一个常量计数器,它在每一代垃圾收集器中显示活动对象。我不想要名字或任何东西,只是总数;当我在游戏中做某些事情时,我可以注意一些事情。
然而,我的问题是,我似乎找不到计算各代人目前活着的总物品的方法。
我甚至考虑过保留一个全局静态字段,它将在每个构造函数中递增并在类终结器中递减。这需要将所述功能手动编码到每个类中,并且不能解决“每代总计”的问题。
你知道我该怎么做吗?
答案 0 :(得分:3)
(问题标题:) “计算排队等待垃圾收集的总对象”
(来自问题的主体:) “然而,我的问题是我似乎无法找到计算各代人目前活着的总物品的方法。”
备注:您的问题的标题和正文要求相反的事情。在标题中,您要求通过任何GC根目录无法再访问的对象数量,而在正文中,您要求“实时”对象,即仍可通过任何GC根目录访问的对象子>
首先我要说可能没有办法做到这一点,主要是因为.NET中的对象不是引用计数,所以它们不能立即标记为“不再需要”当最后一次引用它们消失或超出范围时。我相信.NET的mark-and-compact垃圾收集器只能发现哪些对象是活着的,哪些对象可以在实际的垃圾收集过程中回收(在“标记”阶段)。但是,您似乎需要提前 ,即在GC发生之前。
话虽如此,这可能是您最好的选择:
也许您在.NET的托管框架类库中最好的选择是 performance counters 。但它看起来没有任何合适的计数器可用:有各种性能计数器为您提供各代GC生成的已分配字节数,但AFAIK没有计数活动/死对象的数量。
你可能也想看看 CLR(即运行时)的非托管,基于COM的Debugging API 。鉴于您已检索到ICorDebugProcess5
interface,可能会对这些方法感兴趣:
“获取要在进程中进行垃圾回收的所有对象的枚举器。”
另请参阅this answer至a similar question on SO。
请注意,这是关于要进行垃圾收集的对象,而不是关于活动对象。
“提供有关垃圾收集堆的一般信息,包括它当前是否可枚举。”
如果事实证明托管堆 是可枚举的,您可以使用...
“获取托管堆上对象的枚举器。”
此枚举器返回的对象属于以下类型:
“提供有关托管堆上对象的信息。”
您可能实际上对这些细节不感兴趣,只是对枚举器返回的对象数量感兴趣。
(我自己没有使用过这个API,也许存在一种更好,更有效的方式。)
2015年9月,Microsoft发布了一个名为clrmd
aka Microsoft.Diagnostics.Runtime
on GitHub的托管库。它基于与上面提到的非托管调试API相同的基础。该项目包括documentation about enumerating objects in the GC heap。
顺便说一下。 Ben Watson "Writing High-Performance .NET Code"提供了一本内容非常丰富的书,其中包含有关如何使.NET内存分配和GC更高效的实用技巧。
答案 1 :(得分:1)
垃圾收集器不必收集对象。
......垃圾收集器会发现这个事实 为对象所在的任何一代运行收集器。(如果它 完全运行,它可能不会。 There is no guarantee that the GC 运行。)
(C)Eric Lippert
如果应用程序正常运行且内存消耗没有增加,GC可以让它在不中断的情况下运行。这意味着数字因运行而不同。
如果我是你,我不会花时间来获取世代信息,而只是用尽内存的大小。
简单但不太准确的方法是从GC获取它。
// Determine the best available approximation of the number
// of bytes currently allocated in managed memory.
Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));
如果您看到使用的内存经常增加和减少,那么您可以使用现有的分析器来确定您分配的位置过多,甚至是内存泄漏的位置。