После удаления объектов память не освобождается

Общие вопросы о Unity3D

После удаления объектов память не освобождается

Сообщение Инженер 26 апр 2020, 18:21

Я периодически очищаю пул от лишних объектов. Мне казалось это хорошей идеей, пока не посмотрел в диспетчер задач при тестировании сборки. Объекты удаляются, но память не снижается! То есть когда пул мотает объекты туда-сюда, память не растет. Но стоит инстанцировать несколько тысяч новых объектов, как память вырастает. И так и остается использованной на всегда, даже после удаления объектов полностью (я проверял)!

Что за дела? Я хочу узнать причину, почему это происходит и как очистить память полностью, не перезагружая сцену.

Я думал, может пул поломанный. Для чистоты теста построил отдельный чистый проект с простым скриптом. Никаких других ассетов, текстур и т.д. не используется, только чистые дефолтные кубы, упакованные в два префаба. Один спаунится обычно, по ссылке на GameObject в скрипте, второй с помощью Resources.Load. Я думал, может будет разница, но разницы нет.

Итого чистую сцену могу довести до 1.5 Гб занятой памяти, хотя ни единого объекта в сцене нет. Нужно предварительно наспаунить несколько десятков тысяч объектов, а потом уничтожить их и повторить несколько раз.

Синтаксис:
Используется csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Test
{
    public class PrefomanceMemorySpawnDestroyObjects : MonoBehaviour
    {
        int cycles = 1000;
        public GameObject prefab;
        List<GameObject> list = new List<GameObject>();

        private void Update()
        {
            if (Input.GetKey(KeyCode.Alpha1))
            {
                SpawnPrefab();
            }

            if (Input.GetKey(KeyCode.Alpha2))
            {
                SpawnResource();
            }

            if (Input.GetKeyDown(KeyCode.Alpha3))
            {
                DestroyAll();
            }

            if (Input.GetKeyDown(KeyCode.Alpha4))
            {
                ClearMemory();
            }
        }


        void SpawnPrefab()
        {
            for(int i = 0; i < cycles; i++)
            {
                GameObject go = Instantiate(prefab);
                Vector3 pos = new Vector3(Random.Range(-100f, 100f), Random.Range(-100f, 100f), Random.Range(-100f, 100f));
                go.transform.position = pos;
                list.Add(go);
            }
        }

        void SpawnResource()
        {
            for (int i = 0; i < cycles; i++)
            {
                GameObject go = GameObject.Instantiate(Resources.Load("1", typeof(GameObject))) as GameObject;
                Vector3 pos = new Vector3(Random.Range(-100f, 100f), Random.Range(-100f, 100f), Random.Range(-100f, 100f));
                go.transform.position = pos;
                list.Add(go);
            }
        }

        void DestroyAll()
        {
            foreach(GameObject go in list)
            {
                Destroy(go);
            }
            list = new List<GameObject>();
        }

        void ClearMemory()
        {
            Resources.UnloadUnusedAssets();
            System.GC.Collect();
        }

    }
}
 


Если хотите протестировать, вот unitypackage: https://www.dropbox.com/s/agw1iyxuv3iv738/MemTest.unitypackage?dl=0

Можете еще сборку потестить, в диспетчере задач все в реальном эксперименте можно увидеть. Создайте столько объектов, пока сборка не займет 2 ГБ памяти, а потом нажмите 3- увидите, что теперь где-то 1 гб занимает сборка, хотя изначально было в районе 70-100 мб.
(цифры 1 или 2- спаун, 3- удаление, 4- оптимизация)- https://www.dropbox.com/s/f3w1erpd4zv0nsf/MemoryTest.rar?dl=0
Инженер
UNIт
 
Сообщения: 88
Зарегистрирован: 22 май 2016, 11:13

Re: После удаления объектов память не освобождается

Сообщение 1max1 26 апр 2020, 18:52

Меня давно тоже интересовала эта тема, я даже создал топик на офф форуме, но все похер, видимо их устраивает, то что юнька жрет непомерно и не очищает нифига. Короче, я смирился и тебе советую, хотя, можешь попробовать https://habr.com/ru/post/496460/
Потом расскажешь, как оно)
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: После удаления объектов память не освобождается

Сообщение Woolf 26 апр 2020, 19:43

И тут люди узнали, как работает и что такое GarbageCollector..
Разработчик theFisherOnline - там, где клюёт
Разработчик Atom Fishing II - Первая 3D MMO про рыбалку
Разработчик Atom Fishing - Рыбалка на поплавок, донку, нахлыст, блесну в постъядерный период.
Аватара пользователя
Woolf
Адепт
 
Сообщения: 7179
Зарегистрирован: 02 мар 2009, 16:59

Re: После удаления объектов память не освобождается

Сообщение Jarico 26 апр 2020, 21:19

Чувак! Ты создал объекты, для каждого объекта в нативном пуле создалось место под объект и ресурсам которые он использует, чтобы выгрузить полностью память тебе нужно удалять сам объект и ресурсы которые он испольует...

При загрузке с помощью Resources.Load ты должен каждый ресурс который нужен объекту загружать и назначать, иначе юнити сама загружает ресурсы для объекта но после удаления объекта ссылки на ресурсы теряются и получается так что они валяются в памяти до вызова очистки памяти (очистка происходит при смене сцены)
Github: _https://github.com/redheadgektor
Discord: Конь! Чаю!#9382 (сижу редко)
YouTube: _https://www.youtube.com/channel/UCPQ04Xpbbw2uGc1gsZtO3HQ
Telegram: _https://t.me/redheadgektor
Аватара пользователя
Jarico
Адепт
 
Сообщения: 1084
Зарегистрирован: 06 янв 2019, 17:37
Откуда: 0xDEAD
Skype: none
  • Сайт

Re: После удаления объектов память не освобождается

Сообщение Инженер 26 апр 2020, 23:21

Woolf писал(а):И тут люди узнали, как работает и что такое GarbageCollector..


В коде, как прекрасно видно, я вызываю сборщик мусора. Он не помогает.

Синтаксис:
Используется csharp
        void ClearMemory()
        {
            Resources.UnloadUnusedAssets();
            System.GC.Collect();
        }
 


1max1 писал(а):https://habr.com/ru/post/496460/
Потом расскажешь, как оно)

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

Jarico писал(а):Чувак! Ты создал объекты, для каждого объекта в нативном пуле создалось место под объект и ресурсам которые он использует, чтобы выгрузить полностью память тебе нужно удалять сам объект и ресурсы которые он испольует...


Как-то этот пункт не очень продуман у юнитеков. В примере я спауню кубы без текстур, какие там могут быть ресурсы? Нативные компоненты, что ли? И потом при уничтожении объекта для каждого компонента вызывать Destoy() или UnloadAsset?

Вообще, я думал Resources.UnloadUnusedAssets должен позаботиться об уничтожении не используемых ресурсов.
Инженер
UNIт
 
Сообщения: 88
Зарегистрирован: 22 май 2016, 11:13

Re: После удаления объектов память не освобождается

Сообщение Jarico 26 апр 2020, 23:37

Инженер писал(а):Как-то этот пункт не очень продуман у юнитеков. В примере я спауню кубы без текстур, какие там могут быть ресурсы? Нативные компоненты, что ли? И потом при уничтожении объекта для каждого компонента вызывать Destoy() или UnloadAsset?

Вообще, я думал Resources.UnloadUnusedAssets должен позаботиться об уничтожении не используемых ресурсов.


Я про это узнал когда решил весь контент в папку Resources запихнуть... Запихнуть запихнул а вот потом стал замечать что оперативная забивается и приходилось вообще юнити перезапускать...

Вообще класс Resources подразумевает полный контроль над ресурсами, т.е. для загрузки конкретного объекта...
А для твоих целей подойдут бандлы или Addressables (очень кста удобная фигня с самовыгрузкой контента)
Github: _https://github.com/redheadgektor
Discord: Конь! Чаю!#9382 (сижу редко)
YouTube: _https://www.youtube.com/channel/UCPQ04Xpbbw2uGc1gsZtO3HQ
Telegram: _https://t.me/redheadgektor
Аватара пользователя
Jarico
Адепт
 
Сообщения: 1084
Зарегистрирован: 06 янв 2019, 17:37
Откуда: 0xDEAD
Skype: none
  • Сайт

Re: После удаления объектов память не освобождается

Сообщение Инженер 27 апр 2020, 12:04

Jarico писал(а):Я про это узнал когда решил весь контент в папку Resources запихнуть... Запихнуть запихнул а вот потом стал замечать что оперативная забивается и приходилось вообще юнити перезапускать...


Так, стоп, я кое-что упустил. Ведь у меня в скрипте спаунятся и обычные префабы НЕ из папки ресурсов, а по ссылке на префаб, находящемся в Assets:

public GameObject prefab;

Я предусмотрел, что способ инстанцирования может влиять на память, поэтому решил заодно проверить оба варианта. Память растет точно так же. То есть вообще нет разницы, спаунить из ресурсов с помощью

GameObject.Instantiate(Resources.Load("1", typeof(GameObject))) as GameObject;

или обычным способом:

Instantiate(prefab);

Чем же Resources хуже обычного инстанцирования префабов? Судя по моему тесту, они абсолютно одинаково пожирают память и конкретно пристрастие к Resources тут ни при чем.
Инженер
UNIт
 
Сообщения: 88
Зарегистрирован: 22 май 2016, 11:13

Re: После удаления объектов память не освобождается

Сообщение seaman 27 апр 2020, 20:49

Unity’s garbage collection – which uses the Boehm GC algorithm – is non-generational and non-compacting. “Non-compacting” means that objects in memory are not relocated in order to close gaps between objects.

https://docs.unity3d.com/Manual/BestPra ... ty4-1.html

Т.е. после удаления из кучи объектов образовавшиеся в куче "дырки" не убираются. Отсюда куча не уменьшается. Отсюда память растет.
Дырки используются для размещения новых объектов. Но если объект в дырку не влазит, то куча увеличивается.

В-общем занимаемая память может только увеличиваться...
seaman
Адепт
 
Сообщения: 8352
Зарегистрирован: 24 янв 2011, 12:32
Откуда: Самара

Re: После удаления объектов память не освобождается

Сообщение 1max1 27 апр 2020, 21:14

В-общем занимаемая память может только увеличиваться...

Кайф... :ymparty:
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: После удаления объектов память не освобождается

Сообщение Alex5 27 апр 2020, 21:18

Так, а шо ви таки хочите? :) Это же обычная куча, как в том же си. Хотите кучу без дырок - стройте менеджер. И вручную, полегоньку, тасуйте объекты
Linux это просто
Экономика это просто
Forex это просто
Мой канал на YouTube
Аватара пользователя
Alex5
Старожил
 
Сообщения: 507
Зарегистрирован: 22 авг 2019, 17:37

Re: После удаления объектов память не освобождается

Сообщение Инженер 28 апр 2020, 17:01

seaman писал(а):
Unity’s garbage collection – which uses the Boehm GC algorithm – is non-generational and non-compacting. “Non-compacting” means that objects in memory are not relocated in order to close gaps between objects.

https://docs.unity3d.com/Manual/BestPra ... ty4-1.html

Т.е. после удаления из кучи объектов образовавшиеся в куче "дырки" не убираются. Отсюда куча не уменьшается. Отсюда память растет.
Дырки используются для размещения новых объектов. Но если объект в дырку не влазит, то куча увеличивается.

В-общем занимаемая память может только увеличиваться...


Теперь все ясно, спасибо за ссылку.

Интересно, а Addressable Assets тоже имеет эту проблему? Там упоминается скромное "The address not only loads assets, but also unloads them. References are counted automatically and a robust profiler helps you spot potential memory problems.", но решает ли это проблему расширяющейся кучи? Руководство очень куцое.

Alex5 писал(а):Хотите кучу без дырок - стройте менеджер. И вручную, полегоньку, тасуйте объекты


Это как? Загружать каждый компонент объекта отдельно, а потом их уничтожать отдельно? Что имеется ввиду?
Инженер
UNIт
 
Сообщения: 88
Зарегистрирован: 22 май 2016, 11:13

Re: После удаления объектов память не освобождается

Сообщение Alex5 28 апр 2020, 19:18

Инженер писал(а):Это как? Загружать каждый компонент объекта отдельно, а потом их уничтожать отдельно? Что имеется ввиду?

Не заморачивайтесь. Имеется ввиду то, что можно создать низкоуровневый менеджер памяти, который не будет жрать память. Да, это сложно, новичку не потянуть точно, да и выгода от него будет весьма эфемерна.
Проще изначально просчитать будущую архитектуру на бумаге, отложить в сторону, а через неделю сократить на 10-30%.
Linux это просто
Экономика это просто
Forex это просто
Мой канал на YouTube
Аватара пользователя
Alex5
Старожил
 
Сообщения: 507
Зарегистрирован: 22 авг 2019, 17:37

Re: После удаления объектов память не освобождается

Сообщение Инженер 10 май 2020, 13:22

Значит, вариантов уменьшить кучу без перезагрузки сцены нет? А как в других движках дела обстоят? В Unreal Engine, Godot? Описанное ниже и в них тоже происходит?
"после удаления из кучи объектов образовавшиеся в куче "дырки" не убираются. Отсюда куча не уменьшается. Отсюда память растет. Дырки используются для размещения новых объектов. Но если объект в дырку не влазит, то куча увеличивается."
Инженер
UNIт
 
Сообщения: 88
Зарегистрирован: 22 май 2016, 11:13

Re: После удаления объектов память не освобождается

Сообщение DbIMok 10 май 2020, 14:31

не надо путать Unity память и Mono память. первая это про загрузку/выгрузку ассетов, вторая про то что может почистить GC. вы смотрели в Profiler что происходит?
правильный вопрос - половина ответа. учитесь формулировать вопросы понятно.
Новости > _Telegram чат @unity3d_ru (11.6k/4.8k online) > _Telegram канал @unity_news (4.7k подписчиков) > Телеграм тема > "Спасибо"
Аватара пользователя
DbIMok
Адепт
 
Сообщения: 6372
Зарегистрирован: 31 июл 2009, 14:05

Re: После удаления объектов память не освобождается

Сообщение Инженер 11 май 2020, 22:37

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

Сейчас тыкаю палочкой Unreal Engine 4, главная цель- повторить такой же тест в этом движке и посмотреть, будет ли память так же бесконечно увеличиваться. Пока затык с местными типами в С++, потому что там не Queue, а какой-то TQueue и почему-то не получается записать туда Actor (местный GameObject), хотя делаю вроде все правильно. Если есть чем помочь, прошу посмотреть код: https://forums.unrealengine.com/development-discussion/c-gameplay-programming/1758991-why-can%E2%80%99t-i-announce-the-queue

На крайний случай, если в Unreal все так же плохо, есть еще Unigine. Недавно выпустили бесплатную версию, графоуний впечатляет. Главное, что он заточен под открытые пространства и стриминг объектов, может хоть там этот вопрос с кучей решен. Минус, что вводных уроков нет, кроме официальной документации. Я его немного помучил, столкнулся с отсутствием автозаполнения в Visual Code (баг какой-то) и решил отложить до лучших времен.

Ну и Godot еще есть, тоже можно будет ему проверку памяти устроить. Скоро разрабы поддержку Vulkan добавят, графоний до небес взлетит.

Обнадеживающее знамение: по запросу "heap expansion" находятся запросы только для Unity, для других движков упоминаний об этом свойстве я не нашел. Может быть, из-за меньшей популярности других движков, а может, у них такого минуса нет.
Инженер
UNIт
 
Сообщения: 88
Зарегистрирован: 22 май 2016, 11:13

След.

Вернуться в Общие вопросы

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 17