繁体   English   中英

使用弱引用和GC进行渲染

[英]Rendering using Weak References, and the GC

问题

我最近开始学习C# 我是通过制作游戏来做到这一点的(因为我在C++对此非常熟悉)。

要绘制到后台缓冲区的对象在构造时通过使用对象的弱引用发送的事件进行“注册”。 由于C++智能指针被引用计数,并且(因此)一旦最后一个引用超出范围就被销毁,这对我的目的很有效。 但是,在C# ,情况肯定不是这样。

请考虑以下代码段:

foreach(WeakReference<DrawableObject> drawable in drawables.ToList())
{
    DrawableObject target;
    drawable.TryGetTarget(out target);
    if(target != null)
    {
        spriteBatch.Draw(target.Texture, target.Position, target.Rectangle, target.Colour);
    }
    else
    {
        drawables.Remove(drawable);
    }
}

C# ,主要问题(因为我确定很可能是其他我尚未理解的)是,在对象的最后一次强引用超出范围之后, target不能保证为null


潜在解决方案

强制垃圾收集

我可以事先在适当的时间强制调用GC,但在对该想法进行一些研究后,我发现这很可能是一个坏主意和/或代码中其他问题的迹象。

使用Hide()方法

虽然这种方法对于任何游戏都是必不可少的,但是必须明确地调用Hide()每个可绘制对象都是乏味的并且给出了更多的错误空间。 此外, 什么时候应该调用所有这些Hide() 我也不能依赖于及时收集的父对象,因此将它们放在Finalizer并不能解决问题。

实现IDisposable

与上面类似, using语句的替代using (我不知道在哪里放置,因为对象需要存活直到父母超出范围)。


问题

我能想到的解决方案似乎都没有适当地解决这个问题。 我当然错过了不以这种方式使用弱引用的想法,但是如果找不到可以在当前状态下使用游戏的适当解决方案,则必须考虑这样做。 所有这些归结为一些相关的问题:

  • 这是强制垃圾收集的合适用例吗?

  • 如果没有,我怎么能确定一个对象是否是由于当GC下次运行时要收集的?

  • 有没有办法在对象的最后一次引用超出范围(隐式或显式)时调用对象的方法,而不是等待GC出现?

当然,我对任何可以完全避免这个问题的建议表示感谢。

我打算在这个尝试答案..

你要找的是“我按照游戏规则死了”的逻辑。 不是“那个对象已经死了,因为垃圾收集器说的那么”逻辑。

为此...你需要将你的想法转变为这样的事情:

class DrawableObject {
    public bool IsDead { get; set; }
    public int Health { get; set; }

    // ...
    public void GetShot(int amount) {
        Health -= amount;

        if (Health <= 0)
            IsDead = true;
    }
}

..然后:

foreach (var drawable in drawables) {

    DrawableObject target;
    drawable.TryGetTarget(out target);

    if(target == null || target.IsDead) {
        drawables.Remove(drawable);
    }
    else {
        spriteBatch.Draw(target.Texture, target.Position, target.Rectangle, target.Colour);
    }
}

如果它的null基于你的TryGetXXX逻辑..或者它被你的游戏逻辑标记为死了..将它从可绘制对象列表中删除。 让垃圾收集器随时清理它。

TLDR:将你的对象标记为死亡,并将你的逻辑基于你自己的“我死了”的旗帜。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM