【问题标题】:Counting total objects queued for garbage collection计算排队等待垃圾收集的对象总数
【发布时间】:2015-06-14 05:09:53
【问题描述】:

我想在我的 OpenGL 游戏中添加一个小型调试 UI,它会经常更新,并提供各种调试选项/输出显示。我想要的一件事是一个常量计数器,它显示每一代垃圾收集器中的活动对象。我不想要名字或任何东西,只想要总数;当我在游戏中做某些事情时,我可以注意到的东西。

然而,我的问题是我似乎无法找到一种方法来计算各个世代中当前存活的对象总数。

我什至考虑保留一个全局静态字段,该字段将在每个构造函数中递增,并在类终结器中递减。但是,这需要将所述功能手动编码到每个类中,并且不会解决“每代总数”的问题。

你知道我该怎么做吗?

【问题讨论】:

  • 我会改用ClrMD
  • 如果您没有得到更简单的答案,您可以尝试使用 CLR 的非托管调试和分析 API 来检查 GC:请参阅 this answer 至此 similar question。
  • 建议:使用独立的 .NET 内存分析器来分析您的应用程序可能更容易。

标签: c# garbage-collection


【解决方案1】:

(问题标题:)“统计排队等待垃圾回收的对象总数”

(来自问题的正文:)“然而,我的问题是我似乎无法找到一种方法来计算各个世代中当前存活的对象总数。”

备注:您的问题的标题和正文要求相反的内容。在标题中,您询问的是无法通过任何 GC 根访问的对象数量,而在正文中,您要求的是“活动”对象,即仍然可以通过任何 GC 根访问的对象.

首先让我说可能没有任何方法可以做到这一点,主要是因为 .NET 中的对象没有引用计数,因此不能立即将它们标记为“不再需要”当对它们的最后引用消失或超出范围时。我相信 .NET 的 mark-and-compact 垃圾收集器只会发现哪些对象是活动的,哪些对象可以在实际垃圾收集期间(在“标记”阶段)被回收。但是,您似乎提前需要此信息,即在 GC 发生之前。

话虽如此,这也许是您最好的选择:

  1. 也许您在 .NET 的托管框架类库中的最佳选择是 performance counters。但看起来没有任何合适的计数器可用:有性能计数器可以为您提供在各种 GC 代中分配的字节数,但 AFAIK 没有用于活/死对象数量的计数器。

    李>
  2. 您可能还想看看CLR(即运行时)的非托管、基于COM的Debugging API。鉴于您已检索到 ICorDebugProcess5 interface,这些方法可能会引起您的兴趣:

    “获取进程中要被垃圾回收的所有对象的枚举器。”

    另请参阅 this answer 至 a similar question on SO。

    请注意,这是关于要被垃圾回收的对象,而不是活动对象。

    “提供有关垃圾收集堆的一般信息,包括它当前是否可枚举。”

    如果事实证明托管堆是可枚举的,您可以使用...

    “获取托管堆上对象的枚举器。”

    此枚举器返回的对象属于这种类型:

    “提供有关托管堆上的对象的信息。”

    您可能实际上对这些细节并不感兴趣,而只是对枚举器返回的对象数量感兴趣。

    (我自己没用过这个API,也许有更好更高效的方法。)

  3. 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 效率的可靠技巧。

【讨论】:

  • 我接受了你作为答案,但我不觉得你最初的评论是有效的。我觉得好像标题完全是身体的代名词。
【解决方案2】:

垃圾收集器不必收集对象。

...当垃圾收集器时会发现这个事实 为对象所在的任何一代运行收集器。(如果它 根本运行,它可能不会。 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));

如果您发现使用的内存经常增加和减少,那么您可以使用现有的分析器来确定您在哪里分配过多的内存,甚至是内存泄漏的位置。

【讨论】:

  • 我有点同意你回答的大致方向(尤其是第三段),但你能否详细说明一下你的意思 “垃圾收集器不必收集对象”?
  • @stakx 我的意思是 GC 可能不会在您的应用程序终止之前(甚至之后)运行并最终确定您的对象。 blogs.msdn.com/b/oldnewthing/archive/2010/08/09/10047586.aspx
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-08
  • 2014-04-11
  • 1970-01-01
  • 2012-10-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多