【问题标题】:Is it possible to block reload of some assemblies selectively in Unity Editor?是否可以在 Unity Editor 中选择性地阻止重新加载某些程序集?
【发布时间】:2017-06-12 16:56:15
【问题描述】:

遇到了线程和 Unity 的一些问题,其中如果线程在后台运行,并且编辑器调用重新加载,例如,如果您最终或立即编辑脚本,Unity 将崩溃或冻结。

问题是因为所有程序集都被重新加载,因此线程程序集/dll 有一个悬空指针。

使问题更复杂的是,即使线程真正完成了它的主程序,例如在运行外部可执行文件并关闭该可执行文件或返回退出代码的情况下,线程仍然没有正确清理,仍然可能导致崩溃。中止、取消甚至加入主线程也不起作用。还有 一旦 Unity 重新加载它的所有程序集,就会发生一些奇怪的事情。日志文件总是显示 Unity 成功完成了重新加载,但紧接着,我们就有了悬空指针。

我知道您可以使用

阻止重新加载
EditorApplication.LockReloadAssemblies();

,甚至你可以通过回调预重载来拦截重载......但是如果有办法阻止重新加载所有特定程序集,那将解决崩溃问题。

更简单的是一个文件夹,比如插件,其中的任何程序集都不会重新编译。

这个问题与运行时/播放模式无关,而只是在编辑器内部,因为我正在研究生产工具和插件。

有人知道解决这个非常令人沮丧的问题的方法吗?

【问题讨论】:

  • 5.6 通过检测 dll 已重新编译并自动为您退出播放模式来解决此问题,而不是 NPE,它会抛出一个更温和的消息,说明“播放模式因重新编译二进制文件。”
  • 感谢您的信息。可悲的是,这个问题变得更深了,因为 A)问题完全出在编辑器中,与播放模式无关,并且 B)我根本不希望 dll 重新编译,因为我希望它的状态持续存在,甚至如果我想关闭它,由于与垃圾收集不一致,它仍然会导致悬空指针。然而,这确实让我想知道,如果我将启动该线程的类填充到游戏对象中并将其设置为 DontDestroyOnLoad(this);如果那行得通。
  • 这超出了我的了解。
  • 我对仅适用于播放模式的 DontDestroyOnLoad 有误。在任何时候触发重新加载时,与该游戏对象关联的程序集仍会在编辑器中重新加载。你不能从重新加载中排除程序集的疯狂......除非你可以而且我不知道怎么做。 :(

标签: c# multithreading unity3d unity5


【解决方案1】:

在 Unity 编辑器中使用 Thread 执行一些后台工作时,我也遇到了这个问题。我能够通过使用UnityEditor.Callbacks.DidReloadScripts 中止并重新启动线程来解决挂起问题。这是我测试的代码:

using System.Threading;
using UnityEngine;

public static class Manager1 
{
    public static int Counter = 0;

    private static Thread Thread;

    static Manager1()
    {
        ThreadStart();
    }

    [UnityEditor.Callbacks.DidReloadScripts]
    static void DidReload()
    {
        Restart();
    }

    static void Task()
    {
        while (true)
        {
            Counter++;
            Thread.Sleep(100);
        }
    }

    static void Abort()
    {
        Debug.Log("ABORT");
        Thread.Abort();
        Thread = null;
    }

    static void Restart()
    {
        Abort();
        ThreadStart();
    }

    static void ThreadStart()
    {
        Thread = new Thread(Task);
        Thread.Start();
    }
}

但是,请注意,我必须在线程中添加对Thread.Sleep 的调用。我无法找到有关此的任何信息,但我观察到如果没有该调用,ThreadAbortException 永远不会在线程中引发,并且线程当然永远不会结束。

【讨论】:

  • 根据我的经验和阅读的内容,thread.Abort() 不是关闭线程的正确方法,而且很危险。最好使用 thread.Interrupt();并进行垃圾收集。 thread.Join() 也是可以接受的,但如果线程中的主例程挂起,您将遇到其他问题。不过,在重新加载程序集和清理线程时获取回调的想法是个好主意。
  • 我认为你是对的。我通常看到推荐的方式是设置一个标志来通知线程结束。我认为 Thread.Abort 的主要问题是它无法让您控制线程执行的结束位置 - 在我的情况下,这并不重要。
【解决方案2】:

这是不可能的。我采用的解决 IronPython 内存泄漏的解决方案是将脚本引擎放入它自己的 appdomain 中,从而有效地包含内存泄漏。如果您决定操作编辑器,这是可能的,但如果您将它放在一个线程上,您将遇到麻烦而没有尝试将其分派到主线程。这包括 Debug.Log。

【讨论】:

    猜你喜欢
    • 2014-10-14
    • 2011-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-19
    相关资源
    最近更新 更多