昨天我决定尝试一下国际象棋程序,因为多年来我意识到我从未编写过国际象棋程序。我创建了一个人工智能来评估许多可能的移动/位置并消耗大量内存。但我想如果我每回合都切断对这些数据的引用就可以了。我应该在需要的时候恢复内存。但由于某种原因,这些对象被保留在内存中。即使当我调用 GC.Collect()
时,我发现内存使用量并没有下降,而且,这要归功于 GC
的新 GetGeneration
方法我可以看到我的对象停留在第 2 代(当然,我使用弱引用来保留它们,以便传递给 GetGeneration)。代码并不像人们想象的带有人工智能的国际象棋程序那么大。位于https://github.com/bluemonkmn/Chess 。在本地,我更改了 Program.cs 文件以对本地 board 变量进行弱引用。然后我有一些代码来尝试消除我的引用并检查垃圾收集:
board = board.Clone();
validMoves.Clear();
Console.WriteLine(GC.GetGeneration(wr));
GC.Collect(2);
GC.WaitForFullGCComplete();
GC.WaitForPendingFinalizers();
Console.WriteLine(GC.GetGeneration(wr));
Clone
函数(如果您愿意,您可以在原始项目中看到 - 上面链接)应该制作一个副本,而不引用旧数据。我找不到任何其他对旧对象的引用。然而,对 GC.GetGeneration(wr)
的两次调用都输出 2
。这个程序的数据结构看起来并没有那么复杂。我在主函数中没有那么多变量,因此不难追踪它们并查看可以保存哪些引用。对旧板对象的引用可能来自哪里?
据我所知,唯一可以直接或间接引用 ChessBoard
对象的变量是 board
变量在 Program.cs
的 Play
函数中。其他一切都使用纯 .NET 框架类型,无法引用我的任意类型。
最佳答案
阅读后What is a "rooted reference"?我发现 Debug模式下的引用根系可能与 Release模式下的不同。我发现当我在没有附加调试器的情况下以 Release模式运行时,所有内存都被返回。它在 Release模式下的运行速度也明显加快。我一直预计 Release模式和 Debug模式之间会存在一些差异,但这是我第一次看到内存使用和性能方面存在如此显着的差异。
关于c# - 无法确定第 2 代对象引用的来源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27694015/