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

Muh*_*han 8 garbage-collection unity-game-engine assetbundle unity-webgl

我正在统一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)
    }
Run Code Online (Sandbox Code Playgroud)

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

 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();
        }
        //}
    }
Run Code Online (Sandbox Code Playgroud)

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

在此处输入图片说明

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

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

在此处输入图片说明

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

Muh*_*han 0

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

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

1.不要使用WWW.LoadFromCacheOrDownload

Unity内置的WWW.LoadFromCacheOrDownload是垃圾!严重地!为什么 ?Ben Vinsonunity在他们的博客中也解释道:

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

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

而Unity在他的博客中明确提到使用UnityWebRequest而不是LoadFromCacheOrDownload:

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

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

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

页面重新加载问题的内存增量似乎与 FireFox 内部机制有关。但它发生在 Chrome 中,因为当我检查内存时开发工具是打开的。

当我在 Chrome 中测量选项卡内存时,开发工具就打开了,因此它会随着每次页面刷新而增加内存。这个原因由一位Unity官方在论坛上定义

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

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

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

但实际上我的测试表明这个问题在 fireFox 中仍然存在,而在 Google Chrome 中解决了。

请记住,我经过长期斗争才得到这个答案。

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