【问题标题】:Unity iOS crash when unloading assetbundle scene卸载assetbundle场景时Unity iOS崩溃
【发布时间】:2019-09-24 11:50:15
【问题描述】:

我在另一个项目中分离了一些小游戏,以便将它们全部加载到一个项目中。我已经使用 Unity 2018.4.9 版本成功创建了资产包并将它们放入 StreamingAssets 文件夹中。 Unity Editor 加载和卸载场景成功,但是当我构建 IOS 时,加载场景成功,没问题,但是当我想卸载它时,它给了我这样的内存错误:

我认为当系统尝试删除与资产包相关的游戏对象时会发生此错误。因为当我想在卸载场景之前删除场景中的所有游戏对象时,它会给出同样的错误。此错误仅发生在 iOS 中,而不发生在编辑器中。 Unity Editor 成功卸载资产包场景。这是我加载/卸载资产包及其场景的代码:

运行 UnloadAdditiveScene() 时发生错误

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class MarketplaceBundleGameLoader : MonoBehaviour
{
    AssetBundle myLoadAssetBundle;
    AssetBundle[] assetBundles;
    float progress = 0f;
    List<GameObject> objectsToBeDisabled;

    public bool passingToAnotherScene = false;
    public static string bundlePath;
    public static MarketplaceBundleGameLoader Instance;
    void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            objectsToBeDisabled = new List<GameObject>();
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            DestroyImmediate(gameObject);
        }
    }

    public void AddObjectToBeDisabled(GameObject go)
    {
        objectsToBeDisabled.Add(go);
    }

    public void LoadMultipleBundles(params string[] pathes)
    {
        if (passingToAnotherScene)
        {
            return;
        }
        passingToAnotherScene = true;
        StartCoroutine(LoadMultipleBundlesTask(pathes));
    }

    IEnumerator LoadMultipleBundlesTask(params string[] pathes)
    {
        progress = 0;
        assetBundles = new AssetBundle[pathes.Length];
        Resources.UnloadUnusedAssets();
        yield return FaderManager.Instance.CloseTheatre();
        for (int i = 0; i < objectsToBeDisabled.Count; i++)
        {
            objectsToBeDisabled[i].SetActive(false);
        }
        SceneManager.LoadScene("BundleGameLoader", LoadSceneMode.Additive);
        yield return FaderManager.Instance.OpenTheatre();
        for (int i = 0; i < pathes.Length; i++)
        {
            AssetBundleCreateRequest abcr = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(Path.Combine(StaticVariables.GetStreamingPath(), pathes[i])));
            while (abcr.progress < 0.9f)
            {
                progress = (i / (1f + pathes.Length)) + abcr.progress / (1f + pathes.Length);
                yield return new WaitForFixedUpdate();
            }
            assetBundles[i] = abcr.assetBundle;
        }
        string[] scenePath = assetBundles[0].GetAllScenePaths();
        AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(System.IO.Path.GetFileNameWithoutExtension(scenePath[0]), LoadSceneMode.Additive);
        asyncLoad.allowSceneActivation = false;
        float totalTimer = 0f;
        while (asyncLoad.progress < 0.9f)
        {

            totalTimer += Time.deltaTime;
            progress = ((float)pathes.Length / (pathes.Length + 1)) + asyncLoad.progress / (pathes.Length + 1);
            yield return null;
        }
        progress = 1.05f;
        float waitDifferenceTime = Mathf.Max(0.1f, 3f - totalTimer);
        yield return new WaitForSeconds(waitDifferenceTime);
        Resources.UnloadUnusedAssets();
        yield return FaderManager.Instance.CloseTheatre();
        asyncLoad.allowSceneActivation = true;

        AsyncOperation asyncUnload = SceneManager.UnloadSceneAsync(SceneManager.GetSceneByName("BundleGameLoader"));
        while (asyncUnload.progress < 0.9f)
        {
            yield return null;
        }
        passingToAnotherScene = false;
        yield return FaderManager.Instance.OpenTheatre();
    }


    public float GetProgress()
    {
        return progress;
    }

    public void UnloadAdditiveScene(string unloadName)
    {
        StartCoroutine(UnloadAdditiveSceneSceneTask(unloadName));
    }

    IEnumerator UnloadAdditiveSceneSceneTask(string unloadName)
    {
        yield return FaderManager.Instance.CloseTheatre();
        for (int i = 0; i < assetBundles.Length; i++)
        {
            assetBundles[i].Unload(false);
        }
        yield return new WaitForEndOfFrame();
        AsyncOperation asyncUnload = SceneManager.UnloadSceneAsync(unloadName);
        while(!asyncUnload.isDone)
        {
            yield return new WaitForEndOfFrame();
        }
        yield return new WaitForEndOfFrame();
        SceneManager.SetActiveScene(SceneManager.GetSceneAt(0));
        //AssetBundle.UnloadAllAssetBundles(true);
        // AssetBundle[] bundles = Resources.FindObjectsOfTypeAll<AssetBundle>();
        // //Debug.Log(bundles.Length);
        // for (int i = 1; i < bundles.Length; i++)
        // {
        //     bundles[i].Unload(true);
        // }
        //Resources.UnloadUnusedAssets();
        for (int i = 0; i < objectsToBeDisabled.Count; i++)
        {
            objectsToBeDisabled[i].SetActive(true);
        }
        objectsToBeDisabled.Clear();

        yield return FaderManager.Instance.OpenTheatre();
    }

    // public void loadScene(string sceneName)
    // {
    //  if(passingToAnotherScene)
    //  {
    //      return;
    //  }
    //  passingToAnotherScene = true;
    //  StartCoroutine(loadSceneTask(sceneName));
    // }

    // public IEnumerator loadSceneTask(string sceneName)
    // {
    //  yield return FaderController.Instance.fadeScreen(0.5f);
    //     yield return new WaitForSeconds(0.5f);

    //  SceneManager.LoadScene("SeasonsLoading");

    //  yield return FaderController.Instance.unfadeScreen(0.5f);
    //  AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName);
    //     asyncLoad.allowSceneActivation = false;
    //     float totalTimer = 0f;
    //     while(asyncLoad.progress < 0.9f)
    //     {
    //         totalTimer += Time.deltaTime;
    //         yield return null;
    //     }
    //     float waitDifferenceTime = Mathf.Max(0.1f, 3f - totalTimer);
    //     yield return new WaitForSeconds(waitDifferenceTime);
    //  yield return FaderController.Instance.fadeScreen(0.5f);
    //  asyncLoad.allowSceneActivation = true;
    //  passingToAnotherScene = false;
    //  yield return FaderController.Instance.unfadeScreen(0.5f);

    //     //yield return new WaitForSeconds(0.5f);


    // }

    public void RestartScene(string sceneName)
    {
        if (passingToAnotherScene)
        {
            return;
        }
        passingToAnotherScene = true;
        StartCoroutine(RestartSceneTask(sceneName));
    }

    public IEnumerator RestartSceneTask(string sceneName)
    {
        yield return FaderManager.Instance.CloseTheatre();
        AsyncOperation asyncUnload = SceneManager.UnloadSceneAsync(SceneManager.GetSceneByName(sceneName));
        while (asyncUnload.progress < 0.9f)
        {
            yield return null;
        }
        AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
        while (asyncLoad.progress < 0.9f)
        {
            yield return null;
        }
        passingToAnotherScene = false;
        yield return FaderManager.Instance.OpenTheatre();
    }


    public void ChangeScene(string unloadScene, string loadScene)
    {
        if (passingToAnotherScene)
        {
            return;
        }
        passingToAnotherScene = true;
        StartCoroutine(ChangeSceneTask(unloadScene, loadScene));
    }

    public IEnumerator ChangeSceneTask(string unloadScene, string loadScene)
    {
        yield return FaderManager.Instance.CloseTheatre();
        AsyncOperation asyncUnload = SceneManager.UnloadSceneAsync(SceneManager.GetSceneByName(unloadScene));
        while (asyncUnload.progress < 0.9f)
        {
            yield return null;
        }
        AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(loadScene, LoadSceneMode.Additive);
        while (asyncLoad.progress < 0.9f)
        {
            yield return null;
        }
        passingToAnotherScene = false;
        yield return FaderManager.Instance.OpenTheatre();
    }
}

【问题讨论】:

  • 我的直觉是错误实际上是在您卸载场景并丢弃捆绑包后在循环中引起的,但是,如果它们在旧场景中,则尝试激活对象以禁用这些将是无效的
  • 您好 BugFinder,感谢您的评论。问题是即使您在卸载之前开始破坏场景,也会出现同样的错误。
  • 如果你根本不将它作为协程执行会发生什么
  • Unity 不再支持 SceneManager.UnloadScene 这就是为什么我将 UnloadSceneAsync 与协程一起使用。

标签: ios unity3d memory-leaks assetbundle scene-manager


【解决方案1】:

在播放器设置中禁用“Strip Engine Code”选项解决了我的问题。在 2018.3.4 中,当您禁用此选项时,Xcode 会给出链接器错误。但在 2019.2.6f 中,它可以工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-29
    • 2014-12-07
    • 2012-02-14
    • 1970-01-01
    相关资源
    最近更新 更多