C# 如何避免实时.NET应用程序中的垃圾收集?

C# 如何避免实时.NET应用程序中的垃圾收集?,c#,.net,garbage-collection,real-time,finance,C#,.net,Garbage Collection,Real Time,Finance,我正在编写一个金融C#应用程序,它接收来自网络的消息,根据消息类型将它们转换为不同的对象,并最终在它们上应用应用应用程序业务逻辑 关键是,在应用了业务逻辑之后,我非常确定我再也不需要这个实例了。我不想等待垃圾收集器释放它们,而是想显式地“删除”它们 在C#中是否有更好的方法来实现这一点,我应该使用对象池来始终重用同一组实例,还是有更好的策略 目标是避免垃圾收集在时间关键的进程中使用任何CPU。不要立即删除它们。为每个对象调用垃圾收集器是个坏主意。通常情况下,您根本不想弄乱垃圾收集器,即使时间关键

我正在编写一个金融C#应用程序,它接收来自网络的消息,根据消息类型将它们转换为不同的对象,并最终在它们上应用应用应用程序业务逻辑

关键是,在应用了业务逻辑之后,我非常确定我再也不需要这个实例了。我不想等待垃圾收集器释放它们,而是想显式地“删除”它们

在C#中是否有更好的方法来实现这一点,我应该使用对象池来始终重用同一组实例,还是有更好的策略


目标是避免垃圾收集在时间关键的进程中使用任何CPU。

不要立即删除它们。为每个对象调用垃圾收集器是个坏主意。通常情况下,您根本不想弄乱垃圾收集器,即使时间关键型进程也只是等待发生的竞争条件,如果它们如此敏感的话

但是,如果您知道您的应用程序将处于忙负载期与轻负载期,那么当您到达一个轻负载期时,您可以尝试使用更通用的GC.Collect(),以鼓励在下一个忙负载期之前进行清理。

请看这里:


你可以告诉垃圾收集器你正在做一些关键的事情,它会尽力对你友好。

你可以在一个池中有有限数量的每种类型的实例,并重用已经完成的实例。池的大小取决于您要处理的消息量。

强制执行GC.Collect()通常是个坏主意,让GC做它最擅长的事情。听起来最好的解决方案是使用一个对象池,如果需要的话,可以增加这些对象-我已经成功地使用了这种模式

这样不仅可以避免垃圾收集,还可以避免常规分配成本


最后,您确定GC给您带来了问题吗?在实施任何性能节省解决方案之前,您可能应该测量并证明这一点-您可能会给自己带来不必要的工作

理论上,如果您的CPU负载很重,或者除非确实需要,否则GC不应该运行。但如果必须这样做,您可能希望将所有对象都保存在内存中,可能是一个单实例,并且除非准备好了,否则永远不要清理它们。这可能是保证GC运行的唯一方法。

如果它是绝对时间关键的,那么您应该使用确定性平台,如C/C++。即使调用GC.Collect()也会产生CPU周期


你的问题从一个建议开始,即你想节省内存,但要清除对象。这是一个空间关键优化。你需要决定你真正想要的是什么,因为GC比人更擅长优化这种情况。

对垃圾收集器的行为有一个很好的理解和感受,你就会明白为什么这里的想法不被推荐。除非你真的喜欢CLR花很多时间重新排列内存中的对象


与其每次收到消息时都创建对象的新实例,不如重用已经使用过的对象?这样,您就不会与垃圾收集器发生冲突,堆内存也不会变得支离破碎**

对于每种消息类型,您都可以创建一个池来保存未使用的实例。每当您收到网络消息时,您都会查看消息类型,从相应的池中拉出一个等待的实例,并应用您的业务逻辑。然后,将消息对象的实例放回其池中

您很可能希望使用实例“延迟加载”您的池,以便您的代码可以轻松扩展。因此,您的池类将需要检测何时提取空实例,并在分发它之前填充它。然后,当调用代码将其放回池中时,它就是一个真实的实例

**“对象池是一种允许重用对象而不是分配和取消分配对象的模式,这有助于防止堆碎片和代价高昂的GC压缩。”


试图猜测垃圾收集器通常是一个非常糟糕的主意。在Windows上,垃圾收集器非常高效,可以信赖。这条一般规则有一些值得注意的例外情况——最常见的是一次性事件的发生,你知道这会导致很多旧对象死亡——一旦对象升级到Gen2(寿命最长的),它们往往会挂起

在您提到的例子中,您听起来好像正在生成许多短期对象—这些将导致Gen0集合。无论如何,这种情况发生得相对频繁,而且效率最高。如果愿意的话,您可以通过拥有一个可重用的对象池来避免这些问题,但最好在采取此类操作之前确定GC是否是一个性能问题-CLR探查器是执行此操作的工具

需要注意的是,垃圾收集器在不同的.NET框架上是不同的——在compact框架上(在Xbox 360和移动平台上运行)这是一个非代GC,因此您必须更加小心程序生成的垃圾。

您自己动手——使用对象池并重用这些对象。对这些对象的调用的语义需要隐藏在工厂外观后面。您需要以某种预定义的方式扩展池。也许每次它达到极限时都会加倍——一个高水位算法,或者一个固定的百分比。我强烈建议您不要调用GC.Collect()


当池中的负载足够低时,您可能会收缩池,这最终会触发垃圾收集——让CLR来担心它。

听上去,您似乎在谈论确定性终结(C++中的析构函数),这在C#中是不存在的。最近的
public class MyClass: IDisposable
{
    private bool _disposed;

    public void Dispose()
    {
        Dispose( true );
        GC.SuppressFinalize( this );
    }

    protected virtual void Dispose( bool disposing )
    {
        if( _disposed )    
            return;

        if( disposing )
        {
            // Dispose managed resources here
        }

        _disposed = true;
    }
}