计算排队等待垃圾回收的对象总数

本文关键字:对象 排队 等待 计算 | 更新日期: 2023-09-27 17:55:57

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

然而,我的问题是,我似乎找不到一种方法来计算目前在各个世代中活着的物体总数。

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

你知道我该怎么做吗?

计算排队等待垃圾回收的对象总数

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

(来自问题的正文:)"然而,我的问题是,我似乎找不到一种方法来计算目前在各个世代中活着的物体总数。

备注:你的问题的标题和正文要求相反的东西。在标题中,您要求无法再通过任何 GC 根访问的对象数量,而在正文中,您要求"活动"对象,即仍然可以通过任何 GC 根访问的对象。

首先,

我首先要说的是,可能没有任何方法可以做到这一点,主要是因为 .NET 中的对象不是引用计数的,因此当对它们的最后一个引用消失或超出范围时,无法立即将它们标记为"不再需要"。我相信。NET 的标记和紧凑垃圾收集器仅发现哪些对象处于活动状态,哪些对象可以在实际垃圾回收期间(在"标记"阶段)回收。但是,您似乎希望提前获得此信息,即在GC发生之前。

话虽如此,这里可能是您最好的选择:

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

  2. 您可能还想查看 CLR(即运行时)的非托管、基于 COM 的调试 API。假设您已经检索了ICorDebugProcess5接口,则可能会对以下方法感兴趣:

    • ICorDebugProcess5::EnumerateGCReferences方法:

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

    另请参阅对SO类似问题的回答。

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

    • ICorDebugProcess5::GetGCHeapInformation方法:

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

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

    • ICorDebugProcess5::EnumerateHeap方法:

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

    此枚举器返回的对象属于以下类型:

    • COR_HEAPOBJECT结构:

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

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

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

  3. 2015 年 9 月,Microsoft 在 GitHub 上发布了一个名为 clrmd 又名 Microsoft.Diagnostics.Runtime 的托管库。它基于与上述非托管调试 API 相同的基础。该项目包括有关枚举 GC 堆中的对象的文档。

顺便说一下,Ben Watson有一本内容非常丰富的书,"编写高性能.NET代码",其中包括有关如何使.NET内存分配和GC更有效的可靠提示。

垃圾

回收器不必收集对象。

。当垃圾收集器发现这一事实时为对象所在的任何生成运行收集器。(如果根本运行,它可能没有。不能保证 GC运行。

(C) 埃里克·利珀特

如果应用程序运行正常并且内存消耗没有增加,则 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));

如果您发现使用的内存经常增加和减少,则可以使用现有的探查器来确定您在哪里分配得太糊,甚至内存泄漏在哪里。