Unity WebGL资产包内存未发布

问题描述 投票:8回答:2

我在Unity 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 Class来下载assetbundle(find here),但仍然无法释放内存,有时会出现aw snap错误。

即使当我试图一次又一次地加载一个空的webgl构建时,它会增加内存堆,然后有时候我会得到快照或内存错误和chrome崩溃。

enter image description here

正如您所看到的,初始加载大约为1.2 Mb,但是当我刷新页面并拍摄快照时,它会使快照带来增加的内存。

unity3d garbage-collection unity-webgl assetbundle
2个回答
3
投票

作为一个注释,你永远不会让你的功能完全像你想象的那样完美。有用于清理垃圾和卸载资产的实用工具,但即使你遵循所有最佳实践,你仍然可能无法让Unity清除所有垃圾(它在后台做了很多事情,它将保留分配的内存并且你没有多少可以做到这一点)。如果你对这是为什么感到好奇,我建议他们在Heap Fragmentation以及他们的Memory 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


0
投票

请考虑@Foggzie答案以获得一些最佳实践(我使用了其中一些)!

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

1.不要使用WWW.LoadFromCacheOrDownload

Unity内置WWW.LoadFromCacheOrDownload是废话!认真!为什么? Ben Vinsonunity也在他们的博客中解释:

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

您可能没有意识到的是,只要Unity应用程序启动,此虚拟文件系统就会加载到内存中并保留在内存中。这意味着,如果您使用资产包的默认Unity缓存机制,则将所有这些包的大小添加到游戏的内存要求中,即使它们未加载也是如此。

和Unity在his blog中明确提到使用UnityWebRequest而不是LoadFromCacheOrDownload:

如果您使用新的UnityWebRequest API,则最小化资产包缓存内存开销的长期解决方案是使用WWW构造函数而不是LoadFromCacheOrDownload()或使用UnityWebRequest.GetAssetBundle()而不使用hash / version参数。

然后在XMLHttpRequest级别使用备用缓存机制,该机制将下载的文件直接存储到indexedDB中,绕过内存文件系统。这正是我们最近开发的,它可以在资产商店购买。您可以随意在项目中使用它,并在需要时自定义它。

2. Chrome开发工具打开时,请勿测量内存

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

一旦我用chrome测量我的标签内存,开发工具就会打开,所以每次页面刷新都会增加内存。这个原因由其中一个Unity official at forum定义

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

我不知道Chrome是否会有类似的行为,但为了更好地衡量,最好关闭其Web控制台以确保它不会保持页面活动。

如果某人有可以发布的公共测试用例,这将有助于查明源代码。

但实际上my test suggest认为这个问题仍然存在于fireFox同时解决谷歌Chrome。

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

更新:我发现当你在firefox中重新加载页面时,它会获得双倍的页面内存。所以它是firefox问题,与统一webgl无关。

© www.soinside.com 2019 - 2024. All rights reserved.