【问题标题】:Are Unity game objects managed or unmanaged resources?Unity 游戏对象是托管资源还是非托管资源?
【发布时间】:2015-09-07 11:15:38
【问题描述】:

我有一个类实例化场景层次结构中的几个统一游戏对象。此类实现 IDisposable。我应该将这些游戏对象作为托管资源还是非托管资源来处理?

我正在关注Dispose pattern,那么我应该将 GameObject.Destroy(myGameObject) 之类的调用放在哪里?

谢谢

编辑: 好的,假设我想在该类超出范围时销毁该类实例化的游戏对象。那你会怎么做呢?

编辑 2: 我正在测试处置。我找到了一个解决方案。它不会自动工作,因为无法从不同的线程调用 GameObject.Destroy(myGameObject)。它将抛出一个错误 CompareBaseObjectsInternal。因此,当不再需要时,我调用 myClass.Dispose()。此外,我将 Unity GameObject 作为托管还是非托管处理似乎无关紧要。

myMain()
{
    DisposeTestClass test = new DisposeTestClass();
    //...
    test.Dispose();
}


class DisposeTestClass : System.IDisposable
{

    public GameObject uselessGameobject { get; private set; }

    public DisposeTestClass()
    {           
        uselessGameobject = new GameObject("Useless gameobject");
    }

    #region IDisposable
    private bool _disposed;

    ~DisposeTestClass()
    {
        Debug.Log("~DisposeTestClass()");

        this.Dispose(false);
    }

    public void Dispose()
    {
        Debug.Log("Dispose()");

        this.Dispose(true);
        System.GC.SuppressFinalize(this);

    }

    protected virtual void Dispose(bool disposing)
    {
        Debug.Log("Dispose(bool)");

        if(_disposed)
        {
            Debug.Log("Disposed. Return.");
            return;
        }           

        if(disposing)
        {
            Debug.Log("Disposing of managed resources...");

            // clean up managed resources
            /*
            if(uselessGameobject != null)
            {
                GameObject.Destroy(uselessGameobject);
                Debug.Log("Game object destroyed.");
            }
            else
            {
                Debug.Log("Game object is null.");
            }*/

        }

        Debug.Log("Cleaning up unmanaged resources...");
        // clean up unmanaged resources

        if(uselessGameobject != null)
        {
            GameObject.Destroy(uselessGameobject);
            Debug.Log("Game object destroyed.");
        }
        else
        {
            Debug.Log("Game object is null.");
        }

        // set the flag
        Debug.Log("Setting the disposed flag.");
        this._disposed = true;
    }
    #endregion

}

}

【问题讨论】:

    标签: c# unity3d idisposable


    【解决方案1】:

    不,您不应该实现 IDisposable。但是你可以:)。

    “那么我应该在哪里调用 GameObject.Destroy(myGameObject)” 当你希望你的对象被销毁时?实际上,无论您调用 myContainer.Dispose() 还是 GameObject.Destroy(gObj) 都无关紧要。

    为您实现 IDisposable 的唯一原因是编写“方便”的代码,例如:

    using(var container = new MyContainer())
    using(var somethingElse = new MyObject())
    {
        \\Logic for container and somethingElse 
    }
    

    但在 Unity 中,这是没有意义的。我很难想象在更新中创建然后销毁游戏对象的情况。

    【讨论】:

    • 其实是类不是容器。它只是引用场景中的游戏对象。即使在类的实例不再存在之后,它们仍然存在。查看我的编辑。
    • 由于缺少上下文,我只使用了“容器”。在 Unity 中使用 GameObject.Destroy 进行销毁。即使在那之后,内存可能仍然被游戏对象占用,除非 GC 收集它。 IDisposable 都不会帮助您完全删除对象。它的目的是释放非托管资源。 GameObject 不是非托管资源,因此它不需要 IDisposable。继续存在意味着在现场可见?
    • 是的,那些游戏对象按层次结构留在场景中。
    • 它们是灰色的还是看起来像正常的。如果暂停执行,你能在现场找到它们吗?
    • 是的,他们住在那里。不是灰色的。帖木儿,我设法解决了这个问题。我会尽快发布代码。
    【解决方案2】:

    嗯,我想你有点误解了IDisposableusing 语句的用途。你不应该为了摆脱一个对象而到处实现IDisposable - 这是垃圾收集器的角色,它知道什么时候应该处理一个对象。

    IDisposableusing 语句用作try/finally 语句(当然它在底层要复杂得多)并确保在不再使用对象后立即删除/解析它。这并不总是托管/非托管资源问题。

    使用using 语句并不能确保您的游戏对象将被释放。这完全取决于是否有其他对象指向它。由于它看起来像一个根对象,我相信它会被 GC 尽可能长时间地持有。请注意,即使 GC 对您的对象调用 Dispose(),只要它被引用,它就会一直留在特殊队列中,直到它被释放。

    另一方面,如果您的GameObject 小于Game,更多的是Object,则您不应该考虑使用IDisposable 处理它,只要它没有以某种方式与某个连接/文件/外部资源。一旦你的对象被认为是垃圾,GC 就会申请内存。请注意,IDisposable 是 CLR 处理的有点不同的东西,并不总是可行的方法。

    编辑

    根据您在编辑中提出的问题-基本上,当对象超出范围时,您什么也不做-如果 GC 认为它是垃圾,它将与发生的最接近的 GC 收集一起被删除。这就是为什么 C# 被认为是托管语言以及为什么您不自行释放内存的原因。

    【讨论】:

    • 我了解您对垃圾收集器的看法,请参阅我的编辑。
    • 好吧,即使类的实例超出范围,类创建的游戏对象仍然存在于场景中。我可以编写名为 Cleanup 或 MyDispose 之类的方法来破坏游戏对象并在我不打算使用该类的实例后手动调用它。但是在 Dispose 中处理 Destroy 会很方便。
    • 如果您的对象仍然存在于您的场景中,这意味着它们以某种方式被植根。您能否详细说明“即使在类的实例超出范围后,该类创建的仍然存在于场景中”?
    • GC 不调用 Dispose 方法。 CLR 将 IDisposable 视为任何其他接口。终结器,通常是正确实现 IDisposable 的一部分,它表明对象应该由 GC 特殊处理。
    • @TimurMannapov +1 没错,这是一种心理捷径——CLR 调用 Finalizer,它可以调用 Dispose,尽管不能保证。这只是一个约定,如果在 Finalizer 中显式调用,GC 将间接调用 Dispose。
    猜你喜欢
    • 2013-02-02
    • 1970-01-01
    • 2011-03-26
    • 1970-01-01
    • 2015-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多