Unity пересоздает объекты, но не обновляет ссылки

Форум для самых маленьких, а так же тех, кому недосуг читать справку самостоятельно.

Re: Unity пересоздает объекты, но не обновляет ссылки

Сообщение Razor89 17 июн 2021, 21:46

Нашел я в общем проблему, спустя три дня.
Если вы подпишите Action событие на какую либо функцию при старте скрипта в сцене, а потом перезагрузите сцену но перед этим вручную не уничтожите связь с событием в OnDestroy, все кешированные ссылки скрипта потеряются, точнее оно будет ссылаться на несуществующие ссылки и массивы, и даже доступ до transform не будет возможным. Думаю это все-же баг Unity, а не мои кривые руки, ведь сборщик должен был по идее следить за этим в том числе. Он посчитал, что объект используется даже после фактического уничтожения вместе со сценой, из за того, что на одну из функций скрипта на объекте висит привязка к событию, и в памяти явно что-то багануло, и большую часть массивов связанных с этим объектом в сцене он попросту удалять не стал и все ссылки продолжали вести на уже якобы несуществующие объекты сцены. А у Unity сборщик мусора кастомный, который отличается от сборщика для c# по умолчанию, насколько мне известно.
Дописал Action -= MyFunction в OnDestroy и все чудом заработало даже после перезагрузки сцены.
Не думаю, что это я виноват. Мы все-таки не в С++ прогаем. И это один из типов ошибок, которые вам никогда редактор не покажет в консоли, что еще больше осложняет поиски.
В принципе все предыдущие мои доводы оказались правдивыми, это все так-же имело место быть фактический.
Мне кажется логичным при сборе мусора удалять привязки и объекты на которых они оставались, если я ошибаюсь, может кто-то шарящий за сбор мусора расскажет как правильно, пока я настаиваю на том, что ошибка не моя.
Razor89
UNец
 
Сообщения: 14
Зарегистрирован: 15 июн 2014, 18:08

Re: Unity пересоздает объекты, но не обновляет ссылки

Сообщение Saltant 17 июн 2021, 23:05

Razor89 писал(а):Дописал Action -= MyFunction в OnDestroy и все чудом заработало даже после перезагрузки сцены.
Не думаю, что это я виноват. Мы все-таки не в С++ прогаем. И это один из типов ошибок, которые вам никогда редактор не покажет в консоли, что еще больше осложняет поиски.

В C# всегда было так, что если подписался на ивент, нужно с него и отписаться. Еще со времен винформс, а может еще и с бейсика.
Я на Google Play _https://play.google.com/store/apps/developer?id=Saltant
Аватара пользователя
Saltant
Адепт
 
Сообщения: 2236
Зарегистрирован: 09 окт 2018, 16:40
Откуда: Химки
  • Сайт

Re: Unity пересоздает объекты, но не обновляет ссылки

Сообщение TeslaGan 18 июн 2021, 02:31

Razor89 писал(а): Думаю это все-же баг Unity, а не мои кривые руки, ведь сборщик должен был по идее следить за этим в том числе. Он посчитал, что объект используется даже после фактического уничтожения вместе со сценой, из за того, что на одну из функций скрипта на объекте висит привязка к событию, и в памяти явно что-то багануло, и большую часть массивов связанных с этим объектом в сцене он попросту удалять не стал и все ссылки продолжали вести на уже якобы несуществующие объекты сцены. А у Unity сборщик мусора кастомный, который отличается от сборщика для c# по умолчанию, насколько мне известно.

ну да, ну да... скажите что еще c# ГК умел зомби-объекты убивать... это когда есть 2/3/несколько объектов с взаимными ссылками.... и которые живут вечно(до закрытия приложения), потому что ссылаются друг на друга...
да, в шарпе есть прекрасный инструмент по очистке неиспользуемых ресурсов(Гарбидж коллектор), но даже он не умеет читать мысли программиста. как он может понять нужен тебе этот класс или нет? ссылка есть, значит она что-то значит. плевать что там круговая порука, и они ссылаются друг на друга.... и как раз твоя задача простая... всего то ссылки удалять... и так работают многие ГК, не считая тех, которые пытаются анализировать связи, и прочую фигню...
TeslaGan
UNITрон
 
Сообщения: 315
Зарегистрирован: 01 авг 2015, 18:00

Re: Unity пересоздает объекты, но не обновляет ссылки

Сообщение Razor89 18 июн 2021, 22:51

TeslaGan писал(а):
Razor89 писал(а): Думаю это все-же баг Unity, а не мои кривые руки, ведь сборщик должен был по идее следить за этим в том числе. Он посчитал, что объект используется даже после фактического уничтожения вместе со сценой, из за того, что на одну из функций скрипта на объекте висит привязка к событию, и в памяти явно что-то багануло, и большую часть массивов связанных с этим объектом в сцене он попросту удалять не стал и все ссылки продолжали вести на уже якобы несуществующие объекты сцены. А у Unity сборщик мусора кастомный, который отличается от сборщика для c# по умолчанию, насколько мне известно.

ну да, ну да... скажите что еще c# ГК умел зомби-объекты убивать... это когда есть 2/3/несколько объектов с взаимными ссылками.... и которые живут вечно(до закрытия приложения), потому что ссылаются друг на друга...
да, в шарпе есть прекрасный инструмент по очистке неиспользуемых ресурсов(Гарбидж коллектор), но даже он не умеет читать мысли программиста. как он может понять нужен тебе этот класс или нет? ссылка есть, значит она что-то значит. плевать что там круговая порука, и они ссылаются друг на друга.... и как раз твоя задача простая... всего то ссылки удалять... и так работают многие ГК, не считая тех, которые пытаются анализировать связи, и прочую фигню...

Как понять что мне этот класс не нужен? Очень просто, когда удаляется объект(GameObject) в Unity, вместе с ним удаляются все закрепленные за ним классы, если они не DontDestroyOnLoad и подписки должны автоматом слетать. Или хотя-бы об этом можно писать в консоль.
В моем случае, как я выяснил из тестов, Unity не удалял из памяти даже gameobject на котором висел этот скрипт с открытой подпиской на событие.
Если мы используем UnityEvents, то для них справедливо удаляются все ссылки, насколько я это представляю, еще ни разу с ними проблем не было из за отписок. С Action такая проблема существует, хотя по сути это одно и то-же и по идее можно их приравнивать к стандартным событиям Unity и при сборке мусора удалять ненужные связи, чтобы подобных ситуаций не было. В данном случае отследить точно, что класс больше не нужен, мы вполне можем.
Даже если отмести все что я написал ранее, когда Unity пытается удалить GameObject, но не удаляет его из памяти фактический, об этом тоже можно писать в консоль, проинформировать "что-то не так", а не молчать и ссылки на рефы оставлять даже после перезагрузки. Кроме багов, это еще черевато переполнением физической памяти устройства. У меня почти неделя ушла в никуда из за глупой "ошибки".

ps Зомби объекты, это все-же немного другое...в нашем случае поступала явная команда Destroy для обьекта(это прямая команда которую невозможно по другому интерпретировать как-то и когда сцена выгружается команда поступает на все объекты), которая должна была за собой последовать удаление всех классов, логический. В моем понимании это аксиома которая в данном случае была нарушена. В ином случае получается противоречие параметру DontDestroyOnLoad, то есть мы не удаляем не только объекты DontDestroyOnLoad, но и еще если посчитаем, что их не нужно удалять, даже если была прямая команда Destroy.
Razor89
UNец
 
Сообщения: 14
Зарегистрирован: 15 июн 2014, 18:08

Re: Unity пересоздает объекты, но не обновляет ссылки

Сообщение TeslaGan 19 июн 2021, 01:37

Razor89 писал(а):ps Зомби объекты, это все-же немного другое...в нашем случае поступала явная команда Destroy для обьекта(это прямая команда которую невозможно по другому интерпретировать как-то и когда сцена выгружается команда поступает на все объекты), которая должна была за собой последовать удаление всех классов, логический. В моем понимании это аксиома которая в данном случае была нарушена. В ином случае получается противоречие параметру DontDestroyOnLoad, то есть мы не удаляем не только объекты DontDestroyOnLoad, но и еще если посчитаем, что их не нужно удалять, даже если была прямая команда Destroy.

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

Razor89 писал(а):Как понять что мне этот класс не нужен? Очень просто, когда удаляется объект(GameObject) в Unity, вместе с ним удаляются все закрепленные за ним классы, если они не DontDestroyOnLoad и подписки должны автоматом слетать. Или хотя-бы об этом можно писать в консоль.

т.е. вы предлагаете в каждом объекте сохранять ссылки которые ведут в объект, и из объекта? чтобы потом при вызове быстренько их очищать? или проходить по всем указателям в памяти, чтобы находить кто у нас работает с удаляемыми объектами?
UnityEvent - он написан на базе слабых связей, как раз для тех, кто забывает отписываться от событий не вовремя... хотя и там не все так радужно как вы говорите, хотя...
TeslaGan
UNITрон
 
Сообщения: 315
Зарегистрирован: 01 авг 2015, 18:00

Re: Unity пересоздает объекты, но не обновляет ссылки

Сообщение 1max1 19 июн 2021, 03:41

Если взять кастомный компонент у объекта, а потом удалить объект через Destroy, то ты по прежнему сможешь получать доступ к полям и методам компонента и ошибки null reference не будет, также если вызвать Destroy на объекте, а потом сравнить ссылку на объект с null через Object.ReferenceEquals(go, null), то там всегда будет false (если просто сравнить через go == null, то будет true, так как оператор сравнения GameObject перегружен). Так что, ты должен сам занулять ссылки если это необходимо.
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Unity пересоздает объекты, но не обновляет ссылки

Сообщение Razor89 23 июн 2021, 08:57

т.е. вы предлагаете в каждом объекте сохранять ссылки которые ведут в объект, и из объекта? чтобы потом при вызове быстренько их очищать?

Ну как вариант реализации имеет место быть, думаю. По крайне мере звучит логично на первый "взгляд".
Так-как у Unity совершенно другая специфика работы с C#, которая обычно в корне отличается от работы с софтовыми приложениями, или по крайне мере в достаточной степени отличается, можно было-бы доработать и такой момент с Action на более низком уровне движка. Пересмотреть некоторые моменты в Garbage Collector, что-то дописать на низкий уровень движка, и так далее. Я конечно не сильно вникал, как непосредственно Action работают на низком уровне, но скорее всего подобные вещи вполне можно было бы реализовать и кастомизировать в unity. Как я уже писал выше, отследить что-куда ведет и когда удаляется мы можем, поэтому особых проблем для реализации этого быть по идее не должно. И это бы закрыло достаточно странную дырку во внутренних процессах движка на уровне памяти, как мне видится.

Если взять кастомный компонент у объекта, а потом удалить объект через Destroy, то ты по прежнему сможешь получать доступ к полям и методам компонента и ошибки null reference не будет

Да ладно?) У меня обычно null reference вылетает при удалении обьекта, если обратиться к компоненту которого уже не существует. А еще иногда Missing Reference вылетает в этих случаях. Только если тело функции будет пустым, может быть в этом случае он не вызовет null reference? Потому-что обычно всегда вызывает. Но, конкретно в моем случае, если вернуться к нему, я мог получать доступ даже до transform, что все-таки не нормально.
Razor89
UNец
 
Сообщения: 14
Зарегистрирован: 15 июн 2014, 18:08

Re: Unity пересоздает объекты, но не обновляет ссылки

Сообщение 1max1 23 июн 2021, 13:40

Да ладно?) У меня обычно null reference вылетает при удалении обьекта, если обратиться к компоненту которого уже не существует. А еще иногда Missing Reference вылетает в этих случаях. Только если тело функции будет пустым, может быть в этом случае он не вызовет null reference? Потому-что обычно всегда вызывает. Но, конкретно в моем случае, если вернуться к нему, я мог получать доступ даже до transform, что все-таки не нормально.

Ну на, смотри))

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

Re: Unity пересоздает объекты, но не обновляет ссылки

Сообщение Alkos26Rus 23 июн 2021, 14:44

1max1 писал(а):
Да ладно?) У меня обычно null reference вылетает при удалении обьекта, если обратиться к компоненту которого уже не существует. А еще иногда Missing Reference вылетает в этих случаях. Только если тело функции будет пустым, может быть в этом случае он не вызовет null reference? Потому-что обычно всегда вызывает. Но, конкретно в моем случае, если вернуться к нему, я мог получать доступ даже до transform, что все-таки не нормально.

Ну на, смотри))


Да, действительно, такая же хрень. Это же недороботка, так не должно быть. Удаляя объект, расчитваешь что и вся выделенная память под него очищается, но нет, можно ссылаться на поля и вызывать методы у удаленного объета, бред какой то.
Аватара пользователя
Alkos26Rus
Адепт
 
Сообщения: 1642
Зарегистрирован: 26 ноя 2020, 17:52
Откуда: Москва

Re: Unity пересоздает объекты, но не обновляет ссылки

Сообщение 1max1 23 июн 2021, 15:15

Destroy не очищает память, это не delete как в C++, здесь нельзя явно указать что удалить, здесь есть только ссылки на объект и пока все они не станут null, объект будет существовать. Так что всё правильно, пусть и не так очевидно(
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Unity пересоздает объекты, но не обновляет ссылки

Сообщение Razor89 23 июн 2021, 16:34

1max1 писал(а):Destroy не очищает память, это не delete как в C++, здесь нельзя явно указать что удалить, здесь есть только ссылки на объект и пока все они не станут null, объект будет существовать. Так что всё правильно, пусть и не так очевидно(

Интересно в таком случае, как оно определяет, что ссылка равна null. Никто вручную ведь не очищает связанные ссылки. Полагаю это создает прецеденты для багов. Что, если запрашивать доступ не в Update, а например через секунду времени, объект все еще будет доступен? Возможно в вашем примере есть конфликт GC, потому-что вы просите доступ каждый кадр и GC не успевает завершить очистку. В этом есть логика, чтобы не удалять объект к которому просят доступ. Что то изменится если провести такой эксперимент в LateUpdate, FixedUpdate, WaitForSeconds ? Между Update и всеми другими событиями в проекте, все-таки есть существенная разница. Ваш пример не совсем корректный, как мне показалось. Но, как факт, что это может происходить в Update, познавательно.
ps Просто обычно в Update никто не удаляет объекты.
Razor89
UNец
 
Сообщения: 14
Зарегистрирован: 15 июн 2014, 18:08

Re: Unity пересоздает объекты, но не обновляет ссылки

Сообщение 1max1 23 июн 2021, 16:44

Хоть через 100 лет доступ запроси, пока есть ссылка, никто ничего из памяти не удалит. Если бы я после удаления явно указал scriptA = null; то через N времени память была бы очищена, а так...
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Unity пересоздает объекты, но не обновляет ссылки

Сообщение Razor89 23 июн 2021, 16:49

1max1 писал(а):Хоть через 100 лет доступ запроси, пока есть ссылка, никто ничего из памяти не удалит. Если бы я после удаления явно указал scriptA = null; то через N времени память была бы очищена, а так...

Как в таком случае контролируется переполнение памяти?
Зачастую Destroy довольно часто используется в проекте.
Razor89
UNец
 
Сообщения: 14
Зарегистрирован: 15 июн 2014, 18:08

Re: Unity пересоздает объекты, но не обновляет ссылки

Сообщение 1max1 23 июн 2021, 17:02

Если это что-то весомое и на это есть ссылки, которые больше не используются, то лучше их обнулить. А вообще, я не знаю как уследить за всеми утечками памяти, это сложный вопрос.
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Unity пересоздает объекты, но не обновляет ссылки

Сообщение TeslaGan 23 июн 2021, 17:44

Razor89 писал(а):
1max1 писал(а):Хоть через 100 лет доступ запроси, пока есть ссылка, никто ничего из памяти не удалит. Если бы я после удаления явно указал scriptA = null; то через N времени память была бы очищена, а так...

Как в таком случае контролируется переполнение памяти?
Зачастую Destroy довольно часто используется в проекте.

современные компы имеют столько памяти, что порой не видны эти утечки до поры до времени...
вы же не подгружаете каждый раз картинку, или музыку...

к тому же дестрой не так часто используется последнее время... уже какое время продвигается идея переиспользования объектов(они не удаляются, они просто кэшируются).

p.s. лет дцать назад, когда юнити была еще с лицензией, находил заметку, что тип Destroy высвобождает ссылки на GO или компонент, от объектов юнити. и если мы создаем какой-нибудь контроллер, извольте расширить дестрой, и добавить очистку ссылок в ваших контролерах... т.к. GC не может высвободить объект, на который есть ссылка активная.
TeslaGan
UNITрон
 
Сообщения: 315
Зарегистрирован: 01 авг 2015, 18:00

Пред.След.

Вернуться в Почемучка

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

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