.NET垃圾收集器的效率

时间:2010-04-26 18:33:37

标签: .net garbage-collection

好的,这是交易。 有些人把他们的生命交给了.NET的垃圾收集器,还有一些人根本不相信它。

我是那些部分信任它的人之一,只要它不是非常重要的性能(我知道我知道......性能关键+ .net不是受欢迎的组合),在这种情况下我更喜欢手动处理我的对象和资源。

我要问的是,垃圾收集器真的有多高效或低效的事实?

请不要根据经验分享任何个人意见或可能假设,我想要无偏见的事实。我也不想进行任何亲/讨论,因为它不会回答这个问题。

由于

编辑为了澄清,我基本上是这样说的:无论我们编写什么应用程序,资源是否关键,我们都可以忘记所有事情并让GC处理它或者不能处理它们?

我正在尝试在实际上得到一个GC的答案是什么和不在哪里以及哪里可能会失败,如果存在这样的情况,手动内存管理会成功。它有限制吗?我不知道如何进一步解释我的问题。

我对任何申请都没有任何问题,这是一个理论问题。

5 个答案:

答案 0 :(得分:9)

对大多数应用程序来说足够高效。但是你不必担心GC。在真正热门的系统,低延迟要求,你应该以一种完全避免它的方式编程。我建议你看看Rapid Addition White Paper

  

尽管GC执行得很好   很快,它需要时间来执行,   因此你的垃圾收集   连续运行模式可以   引入不良延迟和   那些潜伏期的变化   应用程序是高度的   对延迟敏感。作为一个   插图,如果你正在处理   每秒100,000条消息   消息使用一个小的临时2   字符串,大约8个字节(这个   字符串编码的功能和   字符串对象的实现)   为每条消息分配。从而   你正在创造近1MB的垃圾   每秒。对于可能的系统   需要提供持续的性能   超过16小时,这意味着   你将不得不清理16个小时x   60分x 60秒x 1MB   内存大约56 GB的内存。   你可以期待的最好的   垃圾收集器就是这样   完全清理它   第0代或第1代收藏品   导致抖动,最糟糕的是它   会导致第2代垃圾   与相关较大的集合   潜伏期飙升。

但是请注意,在避免GC影响方面取消这些技巧非常困难。您真的需要思考您是否正处于需要考虑GC影响的性能要求中。

答案 1 :(得分:5)

我可以告诉你我使用.NET的垃圾收集器遇到的一些问题。

如果您正在运行使用服务器GC的应用程序(例如ASP.NET应用程序),那么您的延迟将真正糟糕,当您的任何线程都没有时,暂停时间大约为一秒取得任何进展。这是因为.NET 4服务器GC是一个停止世界的GC。显然,.NET 4.5将引入微软第一个主要并发服务器GC。

我曾编写一些检测代码来测量并发系统中使用内置集合(如ConcurrentBag)的延迟,并且由于大量堆碎片而导致32位内存不足,因为.NET GC没有对大型物体进行碎片整理。我不得不将基于数组的数据结构替换为分散在数百万个小块中的纯函数数据结构,以避免在大对象堆(LOH)上出现导致碎片的任何内容。

我在GC中发现了像this one这样的错误导致GC泄漏内存,直到所有系统内存耗尽为止,在一个巨大的GC循环中清除了堆,不仅暂停所有线程,甚至暂停其他进程(因为系统已经交换)长达几分钟!

尽管最新的.NET GC中存在“低延迟”设置,但它实际上只是关闭了垃圾收集,因此您的程序会泄漏内存,直到您获得一次大量的GC暂停。微软似乎更喜欢这样的解决方法,如果你想要可用的延迟,就等于说“编写自己的垃圾收集器”。

然而,.NET GC通常非常好,并且在仔细使用时,可以从中获得良好的结果。例如,我最近编写了一个容错服务器,平均实现了114μs的门到门延迟,95%的延迟低于0.5ms。鉴于我在短短几个月内就用F#编写了整个平台,这与最新技术(见herehere)非常接近。实际上,网络对延迟的贡献比.NET GC更多。

答案 2 :(得分:3)

您无需担心这一点。

原因在于,如果您发现GC占用了大量时间的边缘情况,那么您将能够通过进行现场优化来处理它。这不会是世界末日 - 它可能会很容易。

你不太可能找到这样的边缘情况。它真的表现得非常好。如果您在典型的C和C ++实现中只体验过堆分配器,那么.NET GC就是一个完全不同的动物。我很惊讶I wrote this blog post to try and get the point across

答案 3 :(得分:2)

无论您是否使用GC,都无法始终忘记内存分配。一个好的GC实现给你带来的好处是大部分时间你可以不考虑内存分配。但是没有最终的内存分配器。对于一些关键的东西,你必须要知道如何管理内存,这意味着要知道内部是如何完成的。对于GC和手动堆分配都是如此。

某些GC提供实时保证。 “实时”并不意味着“快速”,这意味着分配器响应时间可以有限。这是嵌入式系统所需的保证,例如在平面中驱动电子指令的系统。奇怪的是,使用垃圾收集器比使用手动分配器更容易实现实时保证。

当前.NET实现中的GC 实时;他们具有启发式的效率和快速。请注意,关于在C中使用malloc()进行手动分配(或在C ++中使用new)也可以这样说,因此如果您在实时保证后已经需要使用特殊的东西。如果你不这样做,那么我不希望你为我使用的汽车和飞机设计嵌入式电子设备!

答案 4 :(得分:1)

任何GC算法都会支持某些活动(即:优化)。您必须根据您的使用模式测试GC,以了解它对您的效率。即使其他人研究.net GC的特定行为并产生“事实”和“数字”,您的结果也会大不相同。

我认为这个问题唯一合理的答案轶事。即使在大规模的情况下,大多数人对GC效率也没有问题。它被认为至少与其他托管语言的GC一样高效或更有效。如果您仍然担心,您可能不应该使用托管语言。