Unity WebGL资产捆绑包内存未释放

时间:2019-03-11 13:08:25

标签: unity3d garbage-collection unity-webgl assetbundle

我正在使用以下功能统一加载和缓存资产捆绑包 webgl

 IEnumerator DownloadAndCacheAB(string assetName)
    {
        // Wait for the Caching system to be ready
        while (!Caching.ready)
            yield return null;

        // Load the AssetBundle file from Cache if it exists with the same version or download and store it in the cache
        using (WWW www = WWW.LoadFromCacheOrDownload(finalUrl, 1))
        {

            yield return www;

            if (www.error != null)
            {
                Debug.Log("WWW download had an error:" + www.error);
            }

            AssetBundle bundle = www.assetBundle;

            if (assetName == "")
            {
                GameObject abObject = (GameObject)Instantiate(bundle.mainAsset, gameObject.transform.position, gameObject.transform.rotation);
                abObject.transform.parent = this.transform;
                SetTreeShaderSettings(abObject);
            }
            else
            {
                GameObject abObject = (GameObject)Instantiate(bundle.LoadAsset(assetName), gameObject.transform.position, gameObject.transform.rotation);
                abObject.transform.parent = this.transform;

            }

            // Unload the AssetBundles compressed contents to conserve memory
            bundle.Unload(false);

        } // memory is freed from the web stream (www.Dispose() gets called implicitly)
    }

每当我要删除对象时,我都会使用此功能。

 public void RemoveBundleObject()
    {
        //if (www != null)
        //{
        //    www.Dispose();
        //    www = null;
        if (loadBundleRef != null)
        {
            StopCoroutine(loadBundleRef);
        }
        if (this.gameObject.transform.childCount > 0)
        {
            Destroy(this.gameObject.transform.GetChild(0).gameObject);
            System.GC.Collect();
        }
        //}
    }

如您所见,我正在删除第一个孩子(我是从资产捆绑包中获得的),然后调用GC Collect强制执行垃圾收集器。但是问题是,每次卸载/销毁对象时,内存都不会释放。现在您会认为我如何测量内存?我正在使用here中的WebGLMemoryStats。 在资产捆绑负载反复迭代之后,我得到了这个。

enter image description here

编辑: 我现在正在使用WebRequest类下载Assetbundle(find here),但仍然无法释放内存,有时会出现aw snap错误。

即使我试图一次加载一个空的webgl构建,一次又一次地增加内存堆,然后有时我会遇到aw snap或内存错误以及chrome崩溃的情况。

enter image description here

如您所见,初始负载约为1.2 Mb,但是当我刷新页面并进行快照时,快照带来了增加的内存。

2 个答案:

答案 0 :(得分:3)

请注意,您永远无法使它发挥出您认为的完美功能。有一些用于清理垃圾和卸载资产的实用程序,但是即使您遵循所有最佳实践,您仍然可能无法让Unity清理所有垃圾(它在后台做了很多工作,会保留分配的内存,并且您所占的空间不大可以做到)。如果您对此感到好奇,建议您在Heap FragmentationMemory Optimization Guide上写下它们。


就您对特定项目所做的事情而言,至少可以进行一些改进:

1)避免不惜一切代价使用WWW类。它创建的垃圾多于其价值,不能总是很好地清除,并且在最新版本的Unity中已过时。使用UnityWebRequest下载捆绑软件。

2)不要养成只加载单个资产然后卸载该捆绑包的习惯。如果在运行时发生大量负载,这将导致崩溃,并且是管理软件包的一种非常低效的方式。我注意到您正在呼叫bundle.Unload(false),这意味着捆绑包正在卸载,而装载的预制资产却没有。我建议以一种您可以的方式进行重组:

  1. 加载所需的捆绑包
  2. 从该捆绑包中加载您需要的资产
  3. 等待所有资产的寿命结束
  4. 致电bundle.Unload(true)

3)调用StopCoroutine(loadBundleRef);时要小心(如果loadBundleRef是运行Web请求和捆绑加载逻辑的Coroutine对象)。中断这些异步操作可能会导致内存问题。您应该有一些地方可以确保Web请求和捆绑包加载完全完成,或者在失败时抛出并让游戏恢复。禁止类似StopCoroutine之类的东西来打扰他们。

4)System.GC.Collect();速度很慢,并且垃圾收集还是会定期进行。谨慎使用它,您可能还需要先调用Resources.UnloadUnusedAssets,然后再调用它。

答案 1 :(得分:0)

也请考虑@Foggzie答案以获取一些最佳做法(我使用了其中一些)!

我的代码或测试过程存在两个问题。

1。不要使用WWW.LoadFromCacheOrDownload

Unity内置WWW.LoadFromCacheOrDownload很烂!认真!为什么呢Ben Vinsonunity也在他们的博客中进行了解释:

  

与内存相关的问题的另一个来源是IndexedDB文件系统   由Unity使用。每当您缓存资产捆绑包或使用任何   与文件系统相关的方法,它们存储在虚拟文件系统中   由IndexedDB支持。

     

您可能没有意识到的是此虚拟文件系统已加载   Unity应用程序启动后立即进入并保留在内存中。   这意味着如果您使用默认的Unity缓存机制   对于资产捆绑包,您要将所有捆绑包的大小添加到   游戏的内存需求,即使不是   已加载

his blog中明确提到了Unity,使用UnityWebRequest代替LoadFromCacheOrDownload:

  

如果要使用新的UnityWebRequest API,则可以使用WWW构造函数代替LoadFromCacheOrDownload()或使用不带哈希/版本参数的UnityWebRequest.GetAssetBundle()(不带散列/版本参数)来最大限度地减少资产束缓存的内存开销。

     

然后在XMLHttpRequest级别使用替代的缓存机制,   将下载的文件直接存储到indexedDB中,绕过了   内存文件系统。这正是我们最近开发的   它在资产商店中可用。随时在您的手中使用它   项目并根据需要对其进行自定义。

页面重新加载上的内存增加问题似乎与FireFox内部机制有关。但是由于我在检查内存时打开了dev工具,因此它在chrome中发生。

2。 Chrome开发工具打开时不要测量内存

一旦我在chrome中测量我的选项卡内存,开发工具就会打开,因此每次刷新页面时它都会增加内存。这个原因由Unity official at forum

之一定义
  

需要注意的一点是,在重新加载页面时分析内存使用情况时   在Firefox中,请确保具有Firefox Web控制台(和调试器)   窗口关闭。 Firefox的行为是,如果打开了Web控制台,   使Firefox JS调试器保持活动状态,从而将所有访问的页面固定到   被缓存在内存中,永不回收它们。关闭Firefox网站   页面控制台允许从内存中释放旧页面。

     

我不知道Chrome是否可能具有类似的行为,但可以肯定的是   措施,最好关闭其网络控制台以确保它不会   使页面保持活动状态。

     

如果某人有一个可以发布的公开测试用例,那   将有助于查明来源。

但是实际上my test suggest表示在解决Google Chrome浏览器时,fireFox仍然存在此问题。

记住,经过长时间的努力,我得到了这个答案。

相关问题