9

可以使用哪些优化模式来提高垃圾收集器的性能?

我问的原因是我使用 Compact Framework 做了很多嵌入式软件。在慢速设备上,垃圾收集可能会成为一个问题,我想减少垃圾收集器启动的时间,当它启动时,我希望它更快地完成。我还可以看到,使用垃圾收集器而不是反对它可以帮助改进任何 .NET 或 Java 应用程序,尤其是重型 Web 应用程序。

这是我的一些想法,但我没有做过任何基准测试。

  • 重用临时类/数组(减少分配计数)
  • 将活动对象的数量保持在最低限度(更快的收集)
  • 尝试使用结构而不是类
4

6 回答 6

12

关键是要了解 CF GC 是如何进行分配的。它是一个简单的标记和清除、非分代 GC,具有特定的算法来触发 GC,以及在收集后什么会导致压缩和/或倾斜。在应用程序级别几乎无法控制 GC(唯一可用的方法是收集,它的使用非常有限,因为无论如何您都无法强制压缩)。

对象重用是一个好的开始,但简单地保持对象数量较少可能是最好的工具之一,因为任何收集操作都必须遍历所有根。保持步行距离是一个好主意。如果压缩正在杀死你,那么防止段碎片将有所帮助。大于 64k 的对象在这方面可能会有所帮助,因为它们有自己的段,并且与较小的对象区别对待。

To really understand how the CF GC works, I'd recommend watching the MSDN Webcast on CF memory management.

于 2008-10-06T21:58:57.540 回答
3

最重要的一个方面是最小化分配率。每当分配一个对象时,它就需要稍后进行 GC。现在当然,如果对象很小寿命很短,它将被钉在年轻代中(假设 GC 是分代的)。大型对象倾向于直接进入终身领域。但是完全避免收集会更好。

此外,如果您可以将东西扔到堆栈上,您将享受到更少的 GC 压力。您可以尝试玩弄 GC 选项,但我认为使用分配分析器会更好地帮助您,这样您就可以找到导致问题的地方。

应该注意的是标准库和框架的重量。你包裹几个对象,它会很快填满。请记住,每当 GC 堆上发生某些事情时,它通常会为 GC 簿记使用更多空间。因此,您单独分配的 1000 个指针比相同指针的数组/向量大得多,因为后者可以共享 GC 簿记。另一方面,后者可能会活得更久。

于 2008-10-04T14:31:24.293 回答
2

一个重要的事实是尽可能缩短对象的生命周期。

于 2008-10-04T12:05:26.630 回答
2

结构与类问题是一个复杂的问题……例如,您可能很容易最终使用更多的堆栈空间。而且您当然不想要可变结构。但其他点似乎是明智的,只要你不弯曲设计以适应它。

[编辑]另一个常见的问题是字符串连接;如果您在循环中进行连接,请使用 StringBuilder,它将删除很多中间字符串。可能是 GC 忙于收集所有废弃的字符串?

于 2008-10-04T12:07:17.500 回答
2

另一种选择是在应用程序的非高峰时间使用 GC.Collect() 手动收集垃圾(假设这在 CF 中可用)。这可以减少稍后在您的应用程序中清理所需的对象。

于 2008-10-04T12:24:24.173 回答
0

我在Rotor 2.0上听到了.NET Rocks节目。如果你真的是铁杆,你可以下载Rotor,调整源代码,然后使用你自己修改过的垃圾收集器。

无论如何,该播客有一些关于 GC 的重要信息。我强烈推荐听一下。

于 2008-10-04T12:52:57.223 回答