绘制一张时序图说明Awake到OnDestroy的完整调用链

解读

国内面试官抛出此题,不是让你背生命周期口诀,而是考察三件事:

  1. 能否把“脚本生命周期”与“引擎底层调度”对应起来;
  2. 是否清楚跨组件、跨GameObject、跨帧的调用顺序差异;
  3. 能否在实战踩坑场景(如热更、协程、异步加载)里用生命周期知识快速定位Bug。
    因此,时序图必须以引擎主线程为时间轴,把“Unity C++端Mono/IL2CPP 托管层用户脚本”三级调用关系画清,并标注触发条件线程安全点

知识点

  1. 三级时钟

    • C++ 场景循环(主线程,固定帧率或可变帧率)
    • 托管层调度(UnityEngineInternal.SendMouseEvents、UnityEditor.EditorApplication等)
    • 用户脚本生命周期(MonoBehaviour 虚函数)
  2. 四大阶段(按调用顺序):
    场景加载 → 第一次帧前 → 每帧更新 → 销毁

  3. 关键顺序(同一GameObject多组件):
    Awake → OnEnable → Start → FixedUpdate → Update → LateUpdate → OnDisable → OnDestroy
    同一函数在兄弟组件间Inspector 从上到下顺序;父子级间上而下自下而上(如LateUpdate)。

  4. 特殊注入点

    • 协程在Update与LateUpdate之间由托管层迭代器驱动;
    • yield return null 等待下一帧Update前
    • SceneManager.LoadSceneAsync 触发Additive时,Awake/OnEnable会在加载线程完成后再主线程排队
  5. 热更与Addressables
    InstantiateAsyncAssetBundle.LoadAssetAsync 会导致Awake资源加载线程回调完成后再主线程执行,容易误判为“Awake延迟”

答案

时序图文字描述(从左到右时间轴,纵向分三层):

主线程C++层
│───Scene Load(C++ 场景加载完成)
│───ActivateGameObject(C++ 标记Active=1)

托管层(UnityEngine.CoreModule)
│───UnityEngine.GameObject::Activate
│ ├───MonoBehaviour::Awake(所有脚本按Inspector顺序)
│ └───MonoBehaviour::OnEnable(仅当Active且之前为Inactive)

用户脚本层
│───第一帧入口**
│ ├───UnityEngine.PlayerLoop::EarlyUpdate
│ │ └───SendMouseEvents(输入事件)
│ ├───FixedUpdate(物理时钟)
│ │ └───MonoBehaviour::FixedUpdate
│ ├───Update
│ │ └───MonoBehaviour::Update
│ ├───Yield(协程迭代器)
│ ├───LateUpdate
│ │ └───MonoBehaviour::LateUpdate
│ └───渲染管线(Culling → Rendering → GUI)

销毁阶段
│───GameObject.Destroy(obj, t=0)
│ ├───标记为“待销毁”
│ │───当前帧LateUpdate后
│ │ └───MonoBehaviour::OnDisable(若Active)
│ │───下一帧EarlyUpdate前
│ │ └───MonoBehaviour::OnDestroy(内存未释放)
│ └───GC 不可达时 → 非确定时机Finalizer(~Class)

补充

  • DontDestroyOnLoad 的对象在场景切换时不会调用OnDestroy,但会OnDisable+OnEnable
  • Application.Quit 时,Editor模式会走OnDestroyiOS/Android后台强杀可能跳过

拓展思考

  1. 帧率骤降排查:若Awake里同步加载超大AssetBundle,会卡住主线程直到加载完成,表现是第一帧耗时>300ms,此时应把初始化拆到Start或异步协程
  2. 热更补丁注入时机ILRuntime等热更方案需要在Awake之前完成注册DelegateBridge,否则泛型虚函数MissingMethodException;正确做法是把补丁初始化放在自定义的Manager脚本RuntimeInitializeOnLoadMethod里,早于任何Awake
  3. VR/XR 多线程渲染:当Graphics Jobs开启时,Camera.OnPreCull/OnRenderObject会在渲染线程回调,不能访问Transform.position等主线程数据,需用UnityEngine.Rendering.RenderPipelineManager同步数据,否则随机闪退