Память пакета ресурсов Unity WebGL не выпускается - PullRequest
8 голосов
/ 11 марта 2019

Я загружаю и кэширую Связки активов , используя приведенную ниже функцию в единстве 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 для принудительного сбора мусора.но проблема в том, что моя память не освобождается всякий раз, когда я выгружаю / уничтожаю объект.Теперь вы будете думать, что, как я измеряю память?Я использую WebGLMemoryStats из здесь .И я получаю это после нескольких итераций загрузки assetbundle.

enter image description here

Редактировать: Сейчас я использую класс WebRequest для загрузки assetbundle( найти здесь ), но все еще не удается освободить память и иногда получаю ошибку оснастки.

Даже когда я пытаюсь загрузить пустую сборку webgl снова и снова, это увеличивает кучу памяти изатем, когда я получаю aw snap или ошибку памяти и сбой chrome.

enter image description here

Как вы видите, начальная загрузка составляет около 1,2 Мб, но когда я обновляю страницуи сделать снимок, это снимок приносит с увеличенной памятью.

Ответы [ 2 ]

3 голосов
/ 11 марта 2019

Как примечание, вы никогда не получите, чтобы это функционировало так идеально, как вы думаете. Существуют утилиты для очистки мусора и выгрузки активов, но даже если вы будете следовать всем лучшим рекомендациям, вы все равно не сможете заставить Unity очистить весь мусор (он много делает в фоновом режиме, что сохраняет выделенную память, и вам не так много может с этим поделать). Если вам интересно, почему это так, я бы предложил их рецензирование на Фрагментация кучи , а также Руководство по оптимизации памяти .


Что касается того, что вы делаете со своим конкретным проектом, есть, по крайней мере, некоторые улучшения, которые вы можете сделать:

1) Избегайте использования класса WWW любой ценой. Он создает намного больше мусора, чем стоит, не всегда хорошо очищается и устарел в новейших версиях Unity. Используйте UnityWebRequest для загрузки пакетов.

2) Не имейте привычки загружать пакет только для загрузки одного актива, а затем выгружать этот пакет. Если у вас много нагрузок, возникающих во время выполнения, это приведет к перебоям и является довольно неэффективным способом управления вашими пакетами. Я заметил, что вы звоните bundle.Unload(false), что означает, что связка выгружается, а загруженный сборный актив - нет. Я бы предложил реструктурировать это так, чтобы вы могли:

  1. загрузите нужный вам комплект
  2. загрузить нужные вам ресурсы из этого пакета
  3. дождитесь окончания срока действия всех этих активов до конца
  4. вызов bundle.Unload(true)

3) Будьте осторожны с вызовом StopCoroutine(loadBundleRef); (если loadBundleRef - это Coroutine объект, который выполняет ваш веб-запрос и логику загрузки пакета). Прерывание этих асинхронных операций может привести к проблемам с памятью. У вас должно быть что-то, что гарантирует, что веб-запросы и пакетные загрузки либо завершатся полностью, либо, в случае сбоя, сработают и позволят вашей игре восстановиться. Не позволяйте что-то вроде StopCoroutine прерывать их.

4) System.GC.Collect(); работает медленно и сборка мусора происходит периодически в любом случае. Используйте его экономно, и вы также можете позвонить Resources.UnloadUnusedAssets, прежде чем звонить.

0 голосов
/ 13 апреля 2019

Пожалуйста, рассмотрите также ответ @Foggzie для некоторых лучших практик (я использовал некоторые из них)!

Были две проблемы с моим кодом или процедурой тестирования.

1. Не используйте WWW.LoadFromCacheOrDownload

Unity Встроенный WWW.LoadFromCacheOrDownload - это дерьмо! Шутки в сторону! Зачем ? Бен Винсон и единство также объясняют в своих блогах:

Другим источником проблем, связанных с памятью, является файловая система IndexedDB. используется Unity. Каждый раз, когда вы кэшируете пакет активов или используете любой методы, связанные с файловой системой, они хранятся в виртуальной файловой системе поддержанный IndexedDB.

Что вы можете не осознавать, так это то, что эта виртуальная файловая система загружена в и сохраняется в памяти, как только ваше приложение Unity запускается. Это означает, что если вы используете механизм кэширования Unity по умолчанию для пакетов активов вы добавляете размер всех этих пакетов в требования к памяти для вашей игры , даже если они не загружен .

И Unity ясно упоминается в его блоге , чтобы использовать UnityWebRequest вместо LoadFromCacheOrDownload:

Более долгосрочное решение для минимизации накладных расходов на кеширование пакетов ресурсов - использовать WWW Constructor вместо LoadFromCacheOrDownload () или использовать UnityWebRequest.GetAssetBundle () без параметра hash / version, если вы используете новый API UnityWebRequest.

Затем используйте альтернативный механизм кэширования на уровне XMLHttpRequest, который сохраняет загруженный файл непосредственно в indexedDB, минуя файловая система памяти. Это именно то, что мы разработали в последнее время и он доступен в магазине активов. Не стесняйтесь использовать его в своем проекты и настроить его, если вам нужно.

2. Не измерять память, когда открыты инструменты Chrome Dev

Кажется, что приращение памяти при перезагрузке страницы связано с внутренним механизмом FireFox. Но это происходило в chrome из-за инструментов разработчика, которые были открыты, когда я проверял память.

Как только я измерил память вкладок в chrome, были открыты инструменты разработки, поэтому они увеличивали объем памяти при каждом обновлении страницы. Эта причина определена одним из чиновников Unity на форуме

Следует отметить, что при профилировании использования памяти при перезагрузке страницы в Firefox убедитесь, что у вас есть веб-консоль Firefox (и отладчик) окно закрыто. Firefox ведет себя так: если веб-консоль открыта, поддерживает отладчик Firefox JS, который прикрепляет все посещенные страницы к быть кэшированным в памяти, никогда не возвращая их. Закрытие веб-сайта Firefox Консоль страниц позволяет освобождать старые страницы из памяти.

Я не знаю, может ли Chrome иметь подобное поведение, но насовсем мера, хорошо, чтобы его веб-консоль была закрыта, чтобы убедиться, что она не сохраняя страницы живыми.

Если у кого-то есть общедоступный тестовый пример, который он может опубликовать, было бы полезно определить источник.

Но на самом деле мой тест подсказывает , что эта проблема все еще сохраняется в FireFox при разрешении для Google Chrome.

Помните, я получил этот ответ после долгой борьбы.

Обновление: я обнаружил, что при перезагрузке страницы в Firefox она удваивает память страницы. Так что это проблема Firefox, не связанная с Unity Webgl.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...