计算排队等待垃圾回收的对象总数
本文关键字:对象 排队 等待 计算 | 更新日期: 2023-09-27 17:55:57
我想在我的OpenGL游戏中添加一个小的调试UI,它将经常更新各种调试选项/输出显示。我想要的一件事是一个常量计数器,它显示每一代垃圾回收器中的活动对象。我不想要名字或任何东西,只需要总数;当我在游戏中做某些事情时,我可以盯着的东西。
然而,我的问题是,我似乎找不到一种方法来计算目前在各个世代中活着的物体总数。
我甚至考虑过保留一个全局静态字段,该字段在每个构造函数中递增,在类终结器中递减。不过,这需要将上述功能手动编码到每个类中,并且无法解决"每代总数"的问题。
你知道我该怎么做吗?
(问题标题:)"计算排队等待垃圾回收的对象总数"
(来自问题的正文:)"然而,我的问题是,我似乎找不到一种方法来计算目前在各个世代中活着的物体总数。
备注:你的问题的标题和正文要求相反的东西。在标题中,您要求无法再通过任何 GC 根访问的对象数量,而在正文中,您要求"活动"对象,即仍然可以通过任何 GC 根访问的对象。
首先,我首先要说的是,可能没有任何方法可以做到这一点,主要是因为 .NET 中的对象不是引用计数的,因此当对它们的最后一个引用消失或超出范围时,无法立即将它们标记为"不再需要"。我相信。NET 的标记和紧凑垃圾收集器仅发现哪些对象处于活动状态,哪些对象可以在实际垃圾回收期间(在"标记"阶段)回收。但是,您似乎希望提前获得此信息,即在GC发生之前。
话虽如此,这里可能是您最好的选择:
也许您最好的选择是.NET 的托管框架类库是性能计数器。但看起来没有任何合适的计数器可用:有性能计数器为您提供各个 GC 代中分配的字节数,但 AFAIK 没有用于活动/死对象数的计数器。
您可能还想查看 CLR(即运行时)的非托管、基于 COM 的调试 API。假设您已经检索了
ICorDebugProcess5
接口,则可能会对以下方法感兴趣:-
ICorDebugProcess5::EnumerateGCReferences
方法:
"获取进程中要垃圾回收的所有对象的枚举器。"
另请参阅对SO类似问题的回答。
请注意,这是关于要进行垃圾回收的对象,而不是关于活动对象。
-
ICorDebugProcess5::GetGCHeapInformation
方法:
"提供有关垃圾回收堆的一般信息,包括它当前是否可枚举。"
如果事实证明托管堆是可枚举的,则可以使用...
-
ICorDebugProcess5::EnumerateHeap
方法:
"获取托管堆上对象的枚举器。"
此枚举器返回的对象属于以下类型:
-
COR_HEAPOBJECT
结构:
"提供有关托管堆上的对象的信息。"
您可能实际上对这些细节不感兴趣,而只是对枚举器返回的对象数感兴趣。
(我自己没有使用过这个API,也许有一种更好,更有效的方法。
-
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));
如果您发现使用的内存经常增加和减少,则可以使用现有的探查器来确定您在哪里分配得太糊,甚至内存泄漏在哪里。