【问题标题】:How to call destructor in C # XNA如何在 C# XNA 中调用析构函数
【发布时间】:2011-06-07 17:43:58
【问题描述】:

我有一个对象,只是想在某些事件中销毁它。 XNA中如何调用析构函数?

【问题讨论】:

    标签: c# xna destructor


    【解决方案1】:

    将对象设置为null,垃圾收集器将在下一次运行时将其拾取。

    附带说明,如果对象是您经常创建的东西(敌人、子弹等),那么您可能希望使用pool 而不是删除该对象。这意味着对象会被回收,因此垃圾收集器的调用频率会降低,从而提高性能。

    【讨论】:

    • 天啊,这是你在 .NET 中最不想做的事情
    • @Nick Berardi - 你能解释一下为什么,因为它似乎有理由投反对票吗?为什么将少量对象引用到null 以及使用pool 的建议是您最不想做的事情? @Nasgharet - 什么不起作用?此外,smokeList 听起来像是一个粒子系统。如果是这种情况,您应该在所有对象上使用池,而不是 null
    • @Nashgharet 在您的情况下它不起作用的原因是事件处理程序将对象保持在范围内,因为事件永远不会与对象解除绑定。您需要调用 -= 来删除该事件,然后它才会被收集。
    • @Nick Berardi - 不,它不会立即对记忆产生影响。问题是销毁游戏中的对象(即失去参考)(因为它是XNA)。 IDisposable 模式对于删除当然是有效的,但 OP 并不关心内存删除,而是破坏对象。在实时游戏中(尤其是在 XBox/WP7 上)强制 GC 是粗心的,pooling 仍然比disposing(common objs) 好。从内存的角度来看,没有必要设置为null,但它有帮助当试图从游戏中移除敌人时。子弹什么时候会自动超出范围?
    • @keyboardP 你在说的是设计考虑而不是清理内存,第二个他给出的例子永远不会释放dym对象,直到gameTime对象被释放,因为由事件处理程序创建的强引用。这是事件驱动模型导致的常见问题,因此即使您将其设置为 null,它也不会在 gameTime 被释放之前被释放。
    【解决方案2】:

    虽然您的里程可能会有所不同,但我更喜欢使用我不再需要的对象 IDisposableDispose()。这是特别的。当您使用非托管资源时为 true,但设置 Dispose() 声明意图。

    请参阅GC.SuppressFinalize 上的此资源,了解如何实现IDisposable 的一个很好的示例。

    http://msdn.microsoft.com/en-us/library/system.gc.suppressfinalize.aspx

    【讨论】:

    • 除了只使用 Dispose 之外,您还可以继续遵循 Disposable 模式,这样您就可以随意释放对象,但如果超出范围,则由 GC 处理.
    【解决方案3】:

    将此对象的引用设置为null

    【讨论】:

      【解决方案4】:

      将对象设置为null后,如果出于某种原因想要立即收集对象,请调用GC.Collect()

      【讨论】:

      • 不好的通用建议。调用 GC.Collect 并不能保证它会立即收集,并且实际上最终可能会产生比其价值更多的问题。
      • @Gregory A Beamer 来自 MSDN on GC.Collect“强制立即对所有代进行垃圾收集。”。当然,这一切都取决于是否应该调用GC.Collect。例如。如果一个对象消耗了大量内存,应该尽快释放,GC.Collect很有用。
      • 让我修改一下我仓促发表的声明。 GC 不保证清理任何对象。我喜欢 Rico 的垃圾收集规则:blogs.msdn.com/b/ricom/archive/2004/11/29/271829.aspx
      【解决方案5】:

      什么样的对象?如果是 Disposable/IDisposable 你应该调用 object.Dispose() 否则,您可以只使用 object=null,它会被自动“清理”。这不是您正在使用的 C ;)

      如果您的“对象”实际上是一个复杂类或其中包含更多对象的东西,您可能需要考虑将其设为 IDisposable 类。

      【讨论】:

        【解决方案6】:

        如果对象包含任何非托管资源,则实现IDisposable(并在完成后使用using 或调用Dispose())。

        如果它不包含非托管资源,那么垃圾收集器将在不再引用它时“在某个时候”声明它。

        GC.Collect() 将使垃圾收集器进行收集,如果没有对它的引用,它将“销毁”您的对象。这不是一个好主意,因为它会影响性能(它需要时间并将其他对象提升到更高的一代,从而使它们在被回收之前在内存中的持续时间更长)。

        为什么需要在某个固定时间销毁对象?

        【讨论】:

          【解决方案7】:

          如果您自己处理清理工作,您要做的是调用GC.SuppressFinalize()...通常您在IDisposable 类中使用GC.SuppressFinalize()IDisposable的常用用法见此代码示例:

          http://msdn.microsoft.com/en-us/library/system.gc.suppressfinalize.aspx

          如果您确实需要立即进行垃圾收集:

          var myObj = new MyObject();
          
          // This object will be cleaned up by the Dispose method.
          // Therefore, you should call GC.SupressFinalize to
          // take this object off the finalization queue 
          // and prevent finalization code for this object
          // from executing a second time.
          GC.SuppressFinalize(myObj);
          

          但我提醒你,你真的应该让对象超出范围,让 GC 自然收集对象。只要您不尝试完成它的工作,.NET 运行时在管理内存方面非常有效。

          编辑

          在查看 cmets 之后,我发现您忘记留下一条重要信息,因为您将相关对象绑定到其他对象方法。这意味着您尝试完成的对象在用于监视事件的方法完成之前不会完成,因此在内存中保留了大约一吨额外的对象。

          要打破这个强引用,您可以使用一个名为WeakReference 的对象。或者使用 lambdas 来打破强引用。

          有关使用 Wea​​kReference 的示例,请参见此处 http://msdn.microsoft.com/en-us/library/system.weakreference.aspx

          或者你可以这样做:

          dym.cas += (x, y, z) => gameTime.ElapsedGameTime(x,y,z);
          

          而不是

          dym.cas += gameTime.ElapsedGameTime;
          

          【讨论】:

            猜你喜欢
            • 2020-04-10
            • 2016-10-28
            • 2019-06-26
            • 2018-02-06
            • 2014-05-03
            • 1970-01-01
            • 2020-11-01
            • 2018-06-02
            • 1970-01-01
            相关资源
            最近更新 更多