如何避免实时.NET应用程序中的垃圾回收?我正在编写一个金融C#应用程序,它从网络接收消息,根据消息类型将它们转换为不同的对象,最后将应用程序业务逻辑应用于它们。关键是在应用业务逻辑之后,我很确定我再也不需要这个实例了。我不想等待垃圾收集器释放它们,而是明确地“删除”它们。在C#中是否有更好的方法来执行此操作,我是否应该使用对象池来始终重用同一组实例,或者是否有更好的策略。目标是避免在时间关键进程中使用任何CPU进行垃圾回收。不要马上删除它们。为每个对象调用垃圾收集器不是一个好主意。通常你根本不想打乱垃圾收集器,即使时间关键进程只对等待它们发生的竞争条件敏感。但是,如果您知道您的应用程序将有轻负载和轻负载时段,您可以在达到轻负载时段时尝试更通用的GC.Collect()以鼓励在下一个繁忙时段之前进行清理。看这里:http://msdn.microsoft.com/en-us/library/bb384202.aspx你可以告诉垃圾收集器你现在正在做一些重要的事情,它会对你很好。你自己打了-使用对象池并重用这些对象。调用这些对象的语义需要隐藏在工厂外观之后。您需要以某种预定义的方式扩展池。每次达到限制时可能将大小加倍-高水算法或固定百分比。我强烈建议您不要调用GC.Collect()。当池上的负载变得足够低时,您可以缩小池并最终触发垃圾收集——让CLR来处理它。尝试猜测垃圾收集器通常是一个非常糟糕的主意。在Windows上,垃圾收集器是分代垃圾收集器,可以认为它非常高效。这个一般规则有一些值得注意的例外-最常见的是你知道会导致许多旧对象死亡的事件的发生-一旦对象被提升到Gen2(最长寿命),它们往往会徘徊。在你提到的情况下,听起来你正在生成许多短暂的对象——这些将导致Gen0集合。无论如何,这些经常发生并且是最有效的。如果需要,您可以通过拥有一个可重用对象池来避免它们,但最好在采取此类操作之前确定GC是否是性能问题-CLR分析器是执行此操作的工具。需要注意的是,垃圾收集器在不同的.NET框架上是不同的——在compact框架上(运行在Xbox360和移动平台上)它是一个非分代的GC,所以你必须更加小心你的程序产生的东西垃圾。强制GC.Collect()通常不是一个好主意,让GC做它最擅长的事情。听起来最好的解决方案是使用一个可以在必要时增长的对象池——我已经成功地使用了这个模式。这样您不仅可以避免垃圾收集,还可以避免定期分配成本。最后,您确定GC导致了您的问题吗?在实施任何节能解决方案之前,您应该测量并证明这一点——您可能会造成不必要的工作!“目标是避免垃圾收集在时间关键过程中使用任何CPU”问:如果时间是关键的,你的意思是你正在听一些你不能错过中断的神秘硬件?A:如果是这样,那么C#不是要用的语言,你需要汇编,C或C++。问:如果时间很紧迫,你的意思是管道中有很多消息,你不希望垃圾收集器变慢?A:如果是这样,你就多虑了。根据对象的声音,您的对象非常短暂,这意味着垃圾收集器将非常有效地回收它们,而不会出现任何明显的性能延迟。然而,唯一可以确定的方法是测试它,将它设置为整夜运行以处理不断的测试消息流,如果你能在GC启动时发现你的性能统计数据,我会感到震惊(即使你可以发现它,如果它真的很重要,我会更加惊讶)。如果对垃圾收集器的行为有了很好的理解和感受,您就会明白为什么不推荐您在这里想到的方法。除非你真的喜欢CLR花时间重新排列内存中的对象。申请强度如何?我编写了一个应用程序,以8KB块捕获3个声卡(ManagedDirectX、44.1KHz、立体声、16位),并通过TCP/IP将3个流中的2个发送到另一台计算机。UI为3个通道中的每一个呈现音频电平表和(平滑地)滚动标题/艺术家。这适用于具有XP、1.8GHz、512MB等的PC。该应用程序使用大约5%的CPU。我没有手动调用GC方法。但我确实需要调整一些浪费的东西。我使用RedGate的Ant分析器来研究浪费的部分。一个很棒的工具!我想使用预先分配的字节数组池,但托管DX程序集在内部分配字节缓冲区并将它们返回给应用程序。事实证明,我不必这样做。如果绝对时间紧迫,那么您应该使用像C/C++这样的确定性平台。即使调用GC.Collect()也会产生CPU周期。您的问题始于您的建议,即您要节省内存但要摆脱这些对象。这是一个空间关键优化。你需要决定你真正想要的是什么,因为GC比人类更擅长优化这种情况。从它的声音来看,您似乎在谈论确定性终结(C++中的析构函数),这在C#中不存在。在C#中最接近的东西是Disposable模式。基本上,您实现了IDisposable接口。基本模式是这样的:publicclassMyClass:IDisposable{privatebool_disposed;publicvoidDispose(){Dispose(真);GC.SuppressFinalize(这个);}protectedvirtualvoidDispose(booldisposing){if(_disposed)return;if(disposing){//在这里处理托管资源}_disposed=true;您可以在池中拥有有限数量的每种类型的实例,并重用已经完成的实例。池的大小取决于您要处理的消息量。与其在每次收到消息时都创建对象的新实例,不如重用已经使用过的对象?这样你就不会与垃圾收集器作斗争,你的堆内存也不会碎片化。**对于每种消息类型,您可以创建一个池来保存未使用的实例。每当收到网络消息时,您都会查看消息类型,从适当的池中提取等待实例并应用您的业务逻辑。之后,将该消息对象的实例放回其池中。您很可能希望按实例“延迟加载”池,以便您的代码可以轻松扩展。因此,您的池类将需要检测何时提取了一个空实例并在删除它之前将其填满。然后,当调用代码将它放回池中时,它就是一个真实的实例。**“对象池是一种允许重用对象而不是分配和释放对象的使用模式,这有助于防止堆碎片以及昂贵的GC压缩。”http://geekswithblogs.net/robp/archive/2008/08/07/speedy-c-part-2-optimizing-memory-allocations—pooling-and.aspx理论上,如果您的CPU负载过重,GC不应运行加载或除非真的需要。但是,如果必须这样做,您可能只想将所有对象保留在内存中,也许只是一个单例实例,除非您准备好,否则永远不要清理它们。这可能是保证GC运行的唯一方法。以上是C#学习教程:Howtoavoidgarbagecollectioninreal-time.NETapplications?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
